smartcomply-web-sdk 1.0.61 → 1.0.63
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/camera/CameraManager.d.ts +8 -0
- package/dist/camera/CameraManager.d.ts.map +1 -1
- package/dist/camera/CameraManager.js +13 -2
- package/dist/camera/CameraManager.js.map +1 -1
- package/dist/camera/Permission.d.ts +11 -0
- package/dist/camera/Permission.d.ts.map +1 -1
- package/dist/camera/Permission.js +23 -0
- package/dist/camera/Permission.js.map +1 -1
- package/dist/esm/camera/CameraManager.d.ts +8 -0
- package/dist/esm/camera/CameraManager.d.ts.map +1 -1
- package/dist/esm/camera/CameraManager.js +11 -1
- package/dist/esm/camera/CameraManager.js.map +1 -1
- package/dist/esm/camera/Permission.d.ts +11 -0
- package/dist/esm/camera/Permission.d.ts.map +1 -1
- package/dist/esm/camera/Permission.js +22 -0
- package/dist/esm/camera/Permission.js.map +1 -1
- package/dist/esm/flow/DocumentCapture.d.ts +20 -5
- package/dist/esm/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/esm/flow/DocumentCapture.js +191 -207
- package/dist/esm/flow/DocumentCapture.js.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.js +84 -116
- 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/esm/utils/constants.d.ts +11 -3
- package/dist/esm/utils/constants.d.ts.map +1 -1
- package/dist/esm/utils/constants.js +11 -3
- package/dist/esm/utils/constants.js.map +1 -1
- package/dist/esm/utils/documentRules.d.ts +15 -0
- package/dist/esm/utils/documentRules.d.ts.map +1 -0
- package/dist/esm/utils/documentRules.js +27 -0
- package/dist/esm/utils/documentRules.js.map +1 -0
- package/dist/flow/DocumentCapture.d.ts +20 -5
- package/dist/flow/DocumentCapture.d.ts.map +1 -1
- package/dist/flow/DocumentCapture.js +191 -207
- package/dist/flow/DocumentCapture.js.map +1 -1
- package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
- package/dist/flow/SmartComplyFlow.js +86 -118
- 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 +376 -313
- package/dist/smartcomply.browser.js.map +4 -4
- package/dist/utils/constants.d.ts +11 -3
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +11 -3
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/documentRules.d.ts +15 -0
- package/dist/utils/documentRules.d.ts.map +1 -0
- package/dist/utils/documentRules.js +31 -0
- package/dist/utils/documentRules.js.map +1 -0
- package/package.json +6 -3
|
@@ -5,6 +5,9 @@ const Smartcomply_1 = require("../client/Smartcomply");
|
|
|
5
5
|
const theme_1 = require("./theme");
|
|
6
6
|
const DocumentCapture_1 = require("./DocumentCapture");
|
|
7
7
|
const device_1 = require("../utils/device");
|
|
8
|
+
const documentRules_1 = require("../utils/documentRules");
|
|
9
|
+
const icons_1 = require("./icons");
|
|
10
|
+
const spinner_1 = require("./spinner");
|
|
8
11
|
const STEP_ORDER = [
|
|
9
12
|
"loading",
|
|
10
13
|
"welcome",
|
|
@@ -44,18 +47,6 @@ function resolveIdTypeInfo(typeName, isDocumentFlow) {
|
|
|
44
47
|
.replace(/\s*\(BVN\)\s*/gi, ' ')
|
|
45
48
|
.replace(/\s{2,}/g, ' ')
|
|
46
49
|
.trim();
|
|
47
|
-
// Helper function to check if document requires back side
|
|
48
|
-
const requiresBackSide = (type) => {
|
|
49
|
-
const t = type.toLowerCase();
|
|
50
|
-
return t.includes("voter") ||
|
|
51
|
-
t.includes("driver") ||
|
|
52
|
-
t.includes("license") ||
|
|
53
|
-
t.includes("national id") ||
|
|
54
|
-
t.includes("national id card");
|
|
55
|
-
// Note: NIN document (nin_with_face, nin_slip) does NOT require back side —
|
|
56
|
-
// the NIN card is single-sided. Only the physical NIN slip has a back but
|
|
57
|
-
// the OCR pipeline only needs the front.
|
|
58
|
-
};
|
|
59
50
|
// BVN — always 11 digits
|
|
60
51
|
if (u.includes("BVN") || u.includes("BANK VERIFICATION")) {
|
|
61
52
|
return { icon: "🏦", desc: "Enter your 11-digit Bank Verification Number (BVN)", requiresBack: false };
|
|
@@ -67,7 +58,7 @@ function resolveIdTypeInfo(typeName, isDocumentFlow) {
|
|
|
67
58
|
// Ghana Card / Ghana National ID
|
|
68
59
|
if (u.includes("GHANA")) {
|
|
69
60
|
if (isDocumentFlow)
|
|
70
|
-
return { icon: "🪪", desc: "Capture or upload your Ghana Card", requiresBack:
|
|
61
|
+
return { icon: "🪪", desc: "Capture or upload your Ghana Card", requiresBack: (0, documentRules_1.requiresBackSide)(typeName) };
|
|
71
62
|
return { icon: "🪪", desc: "Enter your Ghana Card number", requiresBack: false };
|
|
72
63
|
}
|
|
73
64
|
// SSNIT (Ghana social security)
|
|
@@ -84,7 +75,7 @@ function resolveIdTypeInfo(typeName, isDocumentFlow) {
|
|
|
84
75
|
return { icon: "🏢", desc: advanced ? "Enter RC number, company name & type" : "Enter your company registration number", requiresBack: false };
|
|
85
76
|
// Voter / PVC
|
|
86
77
|
if (u.includes("VOTER") || u.includes("PVC")) {
|
|
87
|
-
const requiresBack = requiresBackSide(typeName);
|
|
78
|
+
const requiresBack = (0, documentRules_1.requiresBackSide)(typeName);
|
|
88
79
|
return {
|
|
89
80
|
icon: "🗳️",
|
|
90
81
|
desc: isDocumentFlow
|
|
@@ -98,7 +89,7 @@ function resolveIdTypeInfo(typeName, isDocumentFlow) {
|
|
|
98
89
|
return { icon: "📘", desc: isDocumentFlow ? "Capture or upload your passport" : "Enter your passport number", requiresBack: false };
|
|
99
90
|
// Driver's license
|
|
100
91
|
if (u.includes("DRIVER") || u.includes("LICENSE") || u.includes("LICENCE")) {
|
|
101
|
-
const requiresBack = requiresBackSide(typeName);
|
|
92
|
+
const requiresBack = (0, documentRules_1.requiresBackSide)(typeName);
|
|
102
93
|
return {
|
|
103
94
|
icon: "🚗",
|
|
104
95
|
desc: isDocumentFlow
|
|
@@ -109,7 +100,7 @@ function resolveIdTypeInfo(typeName, isDocumentFlow) {
|
|
|
109
100
|
}
|
|
110
101
|
// National ID card (generic)
|
|
111
102
|
if (u.includes("NATIONAL ID") || (u.includes("NATIONAL") && u.includes("CARD"))) {
|
|
112
|
-
const requiresBack = requiresBackSide(typeName);
|
|
103
|
+
const requiresBack = (0, documentRules_1.requiresBackSide)(typeName);
|
|
113
104
|
return {
|
|
114
105
|
icon: "🪪",
|
|
115
106
|
desc: isDocumentFlow
|
|
@@ -240,18 +231,6 @@ function _formatDocType(code) {
|
|
|
240
231
|
}
|
|
241
232
|
// SmartComplyFlow
|
|
242
233
|
// ─────────────────────────────────────────────────────────────────────
|
|
243
|
-
// Add CSS animation keyframes for spin animations
|
|
244
|
-
const style = document.createElement('style');
|
|
245
|
-
style.textContent = `
|
|
246
|
-
@keyframes sc-spin {
|
|
247
|
-
0% { transform: rotate(0deg); }
|
|
248
|
-
100% { transform: rotate(360deg); }
|
|
249
|
-
}
|
|
250
|
-
`;
|
|
251
|
-
if (!document.head.querySelector('style[data-sc-animations]')) {
|
|
252
|
-
style.setAttribute('data-sc-animations', 'true');
|
|
253
|
-
document.head.appendChild(style);
|
|
254
|
-
}
|
|
255
234
|
class SmartComplyFlow {
|
|
256
235
|
constructor(options) {
|
|
257
236
|
this.theme = (0, theme_1.getTheme)("default");
|
|
@@ -623,27 +602,9 @@ class SmartComplyFlow {
|
|
|
623
602
|
// ── Loading ─────────────────────────────────────────────────────
|
|
624
603
|
renderLoading(container) {
|
|
625
604
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px;gap:16px;";
|
|
626
|
-
|
|
627
|
-
spinnerWrap.style.cssText = "position:relative;width:60px;height:60px;flex-shrink:0;";
|
|
628
|
-
const ring = document.createElement("div");
|
|
629
|
-
ring.style.cssText = `
|
|
630
|
-
position:absolute;inset:0;border-radius:50%;
|
|
631
|
-
border:3px solid ${this.theme.border};
|
|
632
|
-
border-top-color:${this.theme.primary};
|
|
633
|
-
animation:sc-spin 0.9s linear infinite;
|
|
634
|
-
`;
|
|
635
|
-
const centre = document.createElement("div");
|
|
636
|
-
centre.style.cssText = `
|
|
637
|
-
position:absolute;inset:0;
|
|
638
|
-
display:flex;align-items:center;justify-content:center;
|
|
639
|
-
font-size:22px;
|
|
640
|
-
`;
|
|
641
|
-
centre.textContent = "\uD83D\uDEE1\uFE0F";
|
|
642
|
-
spinnerWrap.appendChild(ring);
|
|
643
|
-
spinnerWrap.appendChild(centre);
|
|
644
|
-
container.appendChild(spinnerWrap);
|
|
605
|
+
container.appendChild((0, spinner_1.renderSpinner)(this.theme, { size: 60, icon: (0, icons_1.icon)("shield", 22) }));
|
|
645
606
|
const label = document.createElement("div");
|
|
646
|
-
label.style.cssText = `color:${this.theme.text};font-size
|
|
607
|
+
label.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.base}px;font-weight:600;`;
|
|
647
608
|
label.textContent = "Setting up secure session";
|
|
648
609
|
container.appendChild(label);
|
|
649
610
|
const sub = document.createElement("div");
|
|
@@ -662,11 +623,11 @@ class SmartComplyFlow {
|
|
|
662
623
|
iconWrap.style.cssText = `
|
|
663
624
|
width:50px;height:50px;border-radius:14px;
|
|
664
625
|
display:flex;align-items:center;justify-content:center;
|
|
665
|
-
|
|
626
|
+
color:${this.theme.primary};
|
|
666
627
|
background:linear-gradient(135deg,${this.theme.primary}22,${this.theme.primaryGlow});
|
|
667
628
|
border:1.5px solid ${this.theme.primary}33;
|
|
668
629
|
`;
|
|
669
|
-
iconWrap.
|
|
630
|
+
iconWrap.innerHTML = (0, icons_1.icon)(isDocFlow ? "id-card" : "shield", 24);
|
|
670
631
|
topRow.appendChild(iconWrap);
|
|
671
632
|
const badge = document.createElement("div");
|
|
672
633
|
badge.style.cssText = `
|
|
@@ -685,7 +646,7 @@ class SmartComplyFlow {
|
|
|
685
646
|
titleWrap.style.cssText = "display:flex;flex-direction:column;gap:5px;";
|
|
686
647
|
const title = document.createElement("h2");
|
|
687
648
|
title.style.cssText = `
|
|
688
|
-
color:${this.theme.text};font-size
|
|
649
|
+
color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;
|
|
689
650
|
margin:0;line-height:1.2;
|
|
690
651
|
`;
|
|
691
652
|
// W2: Use client brand name in title
|
|
@@ -719,7 +680,7 @@ class SmartComplyFlow {
|
|
|
719
680
|
const stepsWrap = document.createElement("div");
|
|
720
681
|
stepsWrap.style.cssText = `
|
|
721
682
|
width:100%;display:flex;flex-direction:column;gap:0;
|
|
722
|
-
border-radius
|
|
683
|
+
border-radius:${theme_1.RADIUS.md}px;overflow:hidden;
|
|
723
684
|
border:1.5px solid ${this.theme.border};
|
|
724
685
|
`;
|
|
725
686
|
steps.forEach((step, i) => {
|
|
@@ -732,7 +693,7 @@ class SmartComplyFlow {
|
|
|
732
693
|
`;
|
|
733
694
|
const iconEl = document.createElement("div");
|
|
734
695
|
iconEl.style.cssText = `
|
|
735
|
-
width:28px;height:28px;border-radius
|
|
696
|
+
width:28px;height:28px;border-radius:${theme_1.RADIUS.sm}px;flex-shrink:0;
|
|
736
697
|
display:flex;align-items:center;justify-content:center;
|
|
737
698
|
font-size:13px;
|
|
738
699
|
background:${this.theme.primary}12;
|
|
@@ -960,7 +921,7 @@ class SmartComplyFlow {
|
|
|
960
921
|
// Dropdown field
|
|
961
922
|
const select = document.createElement("select");
|
|
962
923
|
select.style.cssText = `
|
|
963
|
-
width:100%;padding:13px 16px;border-radius
|
|
924
|
+
width:100%;padding:13px 16px;border-radius:${theme_1.RADIUS.md}px;
|
|
964
925
|
font-size:15px;
|
|
965
926
|
background:${this.theme.inputBg};
|
|
966
927
|
color:${this.theme.text};
|
|
@@ -995,7 +956,7 @@ class SmartComplyFlow {
|
|
|
995
956
|
fileInput.type = "file";
|
|
996
957
|
fileInput.accept = "image/*";
|
|
997
958
|
fileInput.style.cssText = `
|
|
998
|
-
width:100%;padding:12px 16px;border-radius
|
|
959
|
+
width:100%;padding:12px 16px;border-radius:${theme_1.RADIUS.md}px;
|
|
999
960
|
font-size:14px;font-weight:500;
|
|
1000
961
|
background:${this.theme.inputBg};
|
|
1001
962
|
color:${this.theme.text};
|
|
@@ -1039,7 +1000,7 @@ class SmartComplyFlow {
|
|
|
1039
1000
|
if (rule?.numeric)
|
|
1040
1001
|
input.inputMode = "numeric";
|
|
1041
1002
|
input.style.cssText = `
|
|
1042
|
-
width:100%;padding:14px 16px;border-radius
|
|
1003
|
+
width:100%;padding:14px 16px;border-radius:${theme_1.RADIUS.md}px;
|
|
1043
1004
|
font-size:16px;font-weight:500;
|
|
1044
1005
|
background:${this.theme.inputBg};
|
|
1045
1006
|
color:${this.theme.text};
|
|
@@ -1101,7 +1062,7 @@ class SmartComplyFlow {
|
|
|
1101
1062
|
errorEl.id = "sc-id-error";
|
|
1102
1063
|
errorEl.style.cssText = `
|
|
1103
1064
|
color:${this.theme.error};font-size:13px;display:none;
|
|
1104
|
-
padding:8px 12px;border-radius
|
|
1065
|
+
padding:8px 12px;border-radius:${theme_1.RADIUS.sm}px;background:${this.theme.errorBg};
|
|
1105
1066
|
`;
|
|
1106
1067
|
container.appendChild(errorEl);
|
|
1107
1068
|
// Submit
|
|
@@ -1122,7 +1083,7 @@ class SmartComplyFlow {
|
|
|
1122
1083
|
};
|
|
1123
1084
|
submitBtn.addEventListener("click", async () => {
|
|
1124
1085
|
submitBtn.disabled = true;
|
|
1125
|
-
submitBtn.innerHTML = `<span style="display:inline-flex;align-items:center;justify-content:center;gap:8px;"
|
|
1086
|
+
submitBtn.innerHTML = `<span style="display:inline-flex;align-items:center;justify-content:center;gap:8px;">${(0, spinner_1.renderInlineSpinner)("#fff", 13)}Verifying...</span>`;
|
|
1126
1087
|
errorEl.style.display = "none";
|
|
1127
1088
|
try {
|
|
1128
1089
|
this.verificationResult = await this.sdk.onboarding.verify({
|
|
@@ -1249,11 +1210,11 @@ class SmartComplyFlow {
|
|
|
1249
1210
|
// W13: Pre-warm camera silently while user reads this screen
|
|
1250
1211
|
this._prewarmCamera();
|
|
1251
1212
|
const iconWrap = document.createElement("div");
|
|
1252
|
-
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;
|
|
1253
|
-
iconWrap.
|
|
1213
|
+
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};`;
|
|
1214
|
+
iconWrap.innerHTML = (0, icons_1.icon)("shield", 28);
|
|
1254
1215
|
container.appendChild(iconWrap);
|
|
1255
1216
|
const title = document.createElement("h2");
|
|
1256
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1217
|
+
title.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1257
1218
|
title.textContent = this._ivsName ? `Is this you?` : "Identity Confirmed";
|
|
1258
1219
|
container.appendChild(title);
|
|
1259
1220
|
if (this._ivsName) {
|
|
@@ -1317,12 +1278,25 @@ class SmartComplyFlow {
|
|
|
1317
1278
|
}
|
|
1318
1279
|
// W13: Pre-warm camera while user reads
|
|
1319
1280
|
this._prewarmCamera();
|
|
1281
|
+
// Step badge — pairs with DocumentCapture.showPreview's "Step 1 of 2"
|
|
1282
|
+
// badge shown right after capture, so this doesn't read as unexplained
|
|
1283
|
+
// repetition: that screen checked photo clarity, this one checks the
|
|
1284
|
+
// OCR-extracted data.
|
|
1285
|
+
const stepBadge = document.createElement("div");
|
|
1286
|
+
stepBadge.style.cssText = `
|
|
1287
|
+
display:inline-flex;align-items:center;gap:5px;
|
|
1288
|
+
padding:3px 11px;border-radius:${theme_1.RADIUS.pill}px;
|
|
1289
|
+
font-size:10.5px;font-weight:600;letter-spacing:0.2px;
|
|
1290
|
+
color:${this.theme.primary};background:${this.theme.primary}15;border:1px solid ${this.theme.primary}30;
|
|
1291
|
+
`;
|
|
1292
|
+
stepBadge.textContent = "STEP 2 OF 2 · CHECK WHAT WE READ";
|
|
1293
|
+
container.appendChild(stepBadge);
|
|
1320
1294
|
const iconWrap = document.createElement("div");
|
|
1321
|
-
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;
|
|
1322
|
-
iconWrap.
|
|
1295
|
+
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};`;
|
|
1296
|
+
iconWrap.innerHTML = (0, icons_1.icon)("document", 28);
|
|
1323
1297
|
container.appendChild(iconWrap);
|
|
1324
1298
|
const title = document.createElement("h2");
|
|
1325
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1299
|
+
title.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1326
1300
|
title.textContent = "Are these your details?";
|
|
1327
1301
|
container.appendChild(title);
|
|
1328
1302
|
const sub = document.createElement("p");
|
|
@@ -1391,6 +1365,12 @@ class SmartComplyFlow {
|
|
|
1391
1365
|
container.appendChild(yesBtn);
|
|
1392
1366
|
const noBtn = this.createSecondaryButton("No, retake document");
|
|
1393
1367
|
this._onceClick(noBtn, () => {
|
|
1368
|
+
// Destroy the old DocumentCapture instance before replacing it —
|
|
1369
|
+
// matches the header back-button handler for this same step (see
|
|
1370
|
+
// backTargets.document_confirm) so retaking via either path releases
|
|
1371
|
+
// any still-open camera stream the same way, instead of silently
|
|
1372
|
+
// overwriting this.docCapture without cleanup.
|
|
1373
|
+
this.docCapture?.destroy();
|
|
1394
1374
|
this._confirmRetries++;
|
|
1395
1375
|
this._ocrName = "";
|
|
1396
1376
|
this._ocrDocNumber = "";
|
|
@@ -1408,19 +1388,10 @@ class SmartComplyFlow {
|
|
|
1408
1388
|
// ── W6+W7+W8: OCR Gate (document verification) ───────────────────
|
|
1409
1389
|
renderOcrGate(container) {
|
|
1410
1390
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:14px;padding:20px 0;text-align:center;";
|
|
1411
|
-
|
|
1412
|
-
spinnerWrap.style.cssText = "position:relative;width:52px;height:52px;flex-shrink:0;";
|
|
1413
|
-
const ring = document.createElement("div");
|
|
1414
|
-
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;`;
|
|
1415
|
-
const centre = document.createElement("div");
|
|
1416
|
-
centre.style.cssText = "position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;";
|
|
1417
|
-
centre.textContent = "📄";
|
|
1418
|
-
spinnerWrap.appendChild(ring);
|
|
1419
|
-
spinnerWrap.appendChild(centre);
|
|
1420
|
-
container.appendChild(spinnerWrap);
|
|
1391
|
+
container.appendChild((0, spinner_1.renderSpinner)(this.theme, { size: 52, icon: (0, icons_1.icon)("document", 20) }));
|
|
1421
1392
|
const statusEl = document.createElement("div");
|
|
1422
1393
|
statusEl.setAttribute("aria-live", "polite");
|
|
1423
|
-
statusEl.style.cssText = `color:${this.theme.text};font-size
|
|
1394
|
+
statusEl.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.base}px;font-weight:600;`;
|
|
1424
1395
|
statusEl.textContent = "Reading your document…";
|
|
1425
1396
|
container.appendChild(statusEl);
|
|
1426
1397
|
const subEl = document.createElement("div");
|
|
@@ -1521,7 +1492,7 @@ class SmartComplyFlow {
|
|
|
1521
1492
|
icon.textContent = "📅";
|
|
1522
1493
|
container.appendChild(icon);
|
|
1523
1494
|
const t = document.createElement("h2");
|
|
1524
|
-
t.style.cssText = `color:${this.theme.text};font-size
|
|
1495
|
+
t.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1525
1496
|
t.textContent = "Document Expired";
|
|
1526
1497
|
container.appendChild(t);
|
|
1527
1498
|
const d = document.createElement("p");
|
|
@@ -1547,7 +1518,7 @@ class SmartComplyFlow {
|
|
|
1547
1518
|
icon.textContent = "🔍";
|
|
1548
1519
|
container.appendChild(icon);
|
|
1549
1520
|
const t = document.createElement("h2");
|
|
1550
|
-
t.style.cssText = `color:${this.theme.text};font-size
|
|
1521
|
+
t.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1551
1522
|
t.textContent = "Document Photo Unclear";
|
|
1552
1523
|
container.appendChild(t);
|
|
1553
1524
|
const msg = reason === "image_too_blurry" ? "Your document photo is too blurry. Please retake it in good lighting with a steady hand."
|
|
@@ -1584,11 +1555,11 @@ class SmartComplyFlow {
|
|
|
1584
1555
|
verificationResult: this.verificationResult || undefined,
|
|
1585
1556
|
});
|
|
1586
1557
|
const iconWrap = document.createElement("div");
|
|
1587
|
-
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;
|
|
1588
|
-
iconWrap.
|
|
1558
|
+
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;`;
|
|
1559
|
+
iconWrap.innerHTML = (0, icons_1.icon)("check", 36);
|
|
1589
1560
|
container.appendChild(iconWrap);
|
|
1590
1561
|
const title = document.createElement("h2");
|
|
1591
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1562
|
+
title.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.headingLg}px;font-weight:700;margin:0;`;
|
|
1592
1563
|
title.textContent = "You're all done!";
|
|
1593
1564
|
container.appendChild(title);
|
|
1594
1565
|
const desc = document.createElement("p");
|
|
@@ -1615,7 +1586,7 @@ class SmartComplyFlow {
|
|
|
1615
1586
|
icon.textContent = "⚠️";
|
|
1616
1587
|
container.appendChild(icon);
|
|
1617
1588
|
const t = document.createElement("h2");
|
|
1618
|
-
t.style.cssText = `color:${this.theme.text};font-size
|
|
1589
|
+
t.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1619
1590
|
t.textContent = "Unable to Complete Verification";
|
|
1620
1591
|
container.appendChild(t);
|
|
1621
1592
|
const d = document.createElement("p");
|
|
@@ -1670,15 +1641,12 @@ class SmartComplyFlow {
|
|
|
1670
1641
|
}
|
|
1671
1642
|
this.documentBlob = blob;
|
|
1672
1643
|
// Show scanning state
|
|
1673
|
-
captureContainer.innerHTML =
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔍</div>
|
|
1678
|
-
</div>
|
|
1644
|
+
captureContainer.innerHTML = "";
|
|
1645
|
+
captureContainer.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:14px;padding:28px 20px;";
|
|
1646
|
+
captureContainer.appendChild((0, spinner_1.renderSpinner)(this.theme, { size: 52, icon: (0, icons_1.icon)("search", 20) }));
|
|
1647
|
+
captureContainer.insertAdjacentHTML("beforeend", `
|
|
1679
1648
|
<div style="color:${this.theme.text};font-size:14px;font-weight:600;">Scanning document...</div>
|
|
1680
|
-
<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
|
|
1681
|
-
</div>`;
|
|
1649
|
+
<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>`);
|
|
1682
1650
|
// Create liveness entry with document.
|
|
1683
1651
|
// Use the first collected field value as identifier when available
|
|
1684
1652
|
// (document flow has no data-verification step, so collectedFields is
|
|
@@ -1742,15 +1710,12 @@ class SmartComplyFlow {
|
|
|
1742
1710
|
console.log(`Retrying document processing (attempt ${retryCount}/${maxRetries})`);
|
|
1743
1711
|
// Show retry message
|
|
1744
1712
|
if (captureContainer) {
|
|
1745
|
-
captureContainer.innerHTML =
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔄</div>
|
|
1750
|
-
</div>
|
|
1713
|
+
captureContainer.innerHTML = "";
|
|
1714
|
+
captureContainer.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:16px;padding:28px 20px;text-align:center;";
|
|
1715
|
+
captureContainer.appendChild((0, spinner_1.renderSpinner)(this.theme, { size: 52, icon: (0, icons_1.icon)("refresh", 20) }));
|
|
1716
|
+
captureContainer.insertAdjacentHTML("beforeend", `
|
|
1751
1717
|
<div style="color:${this.theme.text};font-size:14px;font-weight:600;">Retrying...</div>
|
|
1752
|
-
<div style="color:${this.theme.textSecondary};font-size:12px;max-width:240px;line-height:1.5;">Attempt ${retryCount} of ${maxRetries}</div
|
|
1753
|
-
</div>`;
|
|
1718
|
+
<div style="color:${this.theme.textSecondary};font-size:12px;max-width:240px;line-height:1.5;">Attempt ${retryCount} of ${maxRetries}</div>`);
|
|
1754
1719
|
}
|
|
1755
1720
|
// Wait before retry
|
|
1756
1721
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
@@ -1812,7 +1777,7 @@ class SmartComplyFlow {
|
|
|
1812
1777
|
const retryBtn = document.createElement("button");
|
|
1813
1778
|
retryBtn.textContent = "Try Again";
|
|
1814
1779
|
retryBtn.setAttribute("aria-label", "Retake document photo");
|
|
1815
|
-
retryBtn.style.cssText = `margin-top:8px;padding:12px 24px;border-radius
|
|
1780
|
+
retryBtn.style.cssText = `margin-top:8px;padding:12px 24px;border-radius:${theme_1.RADIUS.sm}px;background:${this.theme.primary};color:#fff;border:none;font-size:14px;font-weight:600;cursor:pointer;`;
|
|
1816
1781
|
retryBtn.addEventListener("click", () => this.showStep("document_capture"));
|
|
1817
1782
|
wrap.appendChild(retryBtn);
|
|
1818
1783
|
}
|
|
@@ -1873,6 +1838,12 @@ class SmartComplyFlow {
|
|
|
1873
1838
|
: "liveness_only",
|
|
1874
1839
|
// B4: pass pre-warmed stream so camera.open() is skipped
|
|
1875
1840
|
prewarmedStream: this._prewarmedStream || undefined,
|
|
1841
|
+
colors: {
|
|
1842
|
+
primary: this.theme.primary,
|
|
1843
|
+
success: this.theme.success,
|
|
1844
|
+
error: this.theme.error,
|
|
1845
|
+
warning: this.theme.warning,
|
|
1846
|
+
},
|
|
1876
1847
|
}, ["BLINK"], this.livenessEntryId || undefined)
|
|
1877
1848
|
.then((result) => {
|
|
1878
1849
|
// W11: After submit, end user is done — show "You're all done" screen.
|
|
@@ -1914,14 +1885,14 @@ class SmartComplyFlow {
|
|
|
1914
1885
|
// /v1/sdk/liveness/submit/) are an operator-facing problem, not something
|
|
1915
1886
|
// the end user can act on — never show "wallet"/"balance" language to them.
|
|
1916
1887
|
const isBillingErr = /wallet|balance|insufficient.*fund|payment.*required/i.test(message);
|
|
1917
|
-
const
|
|
1918
|
-
: isNetworkErr ? "
|
|
1919
|
-
: isAuthErr ? "
|
|
1920
|
-
: isDocQuality ? "
|
|
1921
|
-
: isExpiredDoc ? "
|
|
1922
|
-
: isFaceMatch ? "
|
|
1923
|
-
: isBillingErr ? "
|
|
1924
|
-
: "
|
|
1888
|
+
const errorIconName = isCameraErr ? "camera"
|
|
1889
|
+
: isNetworkErr ? "network"
|
|
1890
|
+
: isAuthErr ? "clock"
|
|
1891
|
+
: isDocQuality ? "search"
|
|
1892
|
+
: isExpiredDoc ? "calendar"
|
|
1893
|
+
: isFaceMatch ? "face"
|
|
1894
|
+
: isBillingErr ? "warning"
|
|
1895
|
+
: "close";
|
|
1925
1896
|
const errorTitle = isCameraErr ? "Camera Access Required"
|
|
1926
1897
|
: isNetworkErr ? "Connection Problem"
|
|
1927
1898
|
: isAuthErr ? "Session Expired"
|
|
@@ -1950,14 +1921,14 @@ class SmartComplyFlow {
|
|
|
1950
1921
|
iconWrap.style.cssText = `
|
|
1951
1922
|
width:72px;height:72px;border-radius:50%;
|
|
1952
1923
|
display:flex;align-items:center;justify-content:center;
|
|
1953
|
-
|
|
1924
|
+
color:${this.theme.error};
|
|
1954
1925
|
background:${this.theme.errorBg};
|
|
1955
1926
|
border:3px solid ${this.theme.error};
|
|
1956
1927
|
`;
|
|
1957
|
-
iconWrap.
|
|
1928
|
+
iconWrap.innerHTML = (0, icons_1.icon)(errorIconName, 28);
|
|
1958
1929
|
wrapper.appendChild(iconWrap);
|
|
1959
1930
|
const title = document.createElement("h2");
|
|
1960
|
-
title.style.cssText = `color:${this.theme.text};font-size
|
|
1931
|
+
title.style.cssText = `color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;margin:0;`;
|
|
1961
1932
|
title.textContent = errorTitle;
|
|
1962
1933
|
wrapper.appendChild(title);
|
|
1963
1934
|
const desc = document.createElement("p");
|
|
@@ -1996,7 +1967,7 @@ class SmartComplyFlow {
|
|
|
1996
1967
|
this.headerBackBtn.innerHTML = "←";
|
|
1997
1968
|
this.headerBackBtn.setAttribute("aria-label", "Go back to previous step");
|
|
1998
1969
|
this.headerBackBtn.style.cssText = `
|
|
1999
|
-
width:30px;height:30px;border-radius
|
|
1970
|
+
width:30px;height:30px;border-radius:${theme_1.RADIUS.sm}px;flex-shrink:0;
|
|
2000
1971
|
display:none;align-items:center;justify-content:center;
|
|
2001
1972
|
border:1.5px solid ${this.theme.border};cursor:pointer;
|
|
2002
1973
|
font-size:16px;line-height:1;
|
|
@@ -2054,7 +2025,7 @@ class SmartComplyFlow {
|
|
|
2054
2025
|
closeBtn.innerHTML = "✕";
|
|
2055
2026
|
closeBtn.setAttribute("aria-label", "Close identity verification");
|
|
2056
2027
|
closeBtn.style.cssText = `
|
|
2057
|
-
width:32px;height:32px;border-radius
|
|
2028
|
+
width:32px;height:32px;border-radius:${theme_1.RADIUS.sm}px;flex-shrink:0;
|
|
2058
2029
|
display:flex;align-items:center;justify-content:center;
|
|
2059
2030
|
border:none;cursor:pointer;font-size:16px;
|
|
2060
2031
|
background:${this.theme.shimmer};color:${this.theme.textMuted};
|
|
@@ -2091,7 +2062,7 @@ class SmartComplyFlow {
|
|
|
2091
2062
|
createStepTitle(text) {
|
|
2092
2063
|
const el = document.createElement("h3");
|
|
2093
2064
|
el.style.cssText = `
|
|
2094
|
-
color:${this.theme.text};font-size
|
|
2065
|
+
color:${this.theme.text};font-size:${theme_1.TYPE.heading}px;font-weight:700;
|
|
2095
2066
|
margin:0;
|
|
2096
2067
|
`;
|
|
2097
2068
|
el.textContent = text;
|
|
@@ -2101,7 +2072,7 @@ class SmartComplyFlow {
|
|
|
2101
2072
|
const card = document.createElement("button");
|
|
2102
2073
|
card.setAttribute("aria-label", subtitle ? `${title}: ${subtitle}` : title);
|
|
2103
2074
|
card.style.cssText = `
|
|
2104
|
-
width:100%;padding:13px 16px;border-radius
|
|
2075
|
+
width:100%;padding:13px 16px;border-radius:${theme_1.RADIUS.md}px;
|
|
2105
2076
|
background:${this.theme.cardBg};
|
|
2106
2077
|
border:2px solid ${this.theme.border};
|
|
2107
2078
|
cursor:pointer;text-align:left;
|
|
@@ -2141,7 +2112,7 @@ class SmartComplyFlow {
|
|
|
2141
2112
|
const btn = document.createElement("button");
|
|
2142
2113
|
btn.textContent = text;
|
|
2143
2114
|
btn.style.cssText = `
|
|
2144
|
-
width:100%;padding:14px;border-radius
|
|
2115
|
+
width:100%;padding:14px;border-radius:${theme_1.RADIUS.md}px;
|
|
2145
2116
|
font-size:15px;font-weight:600;
|
|
2146
2117
|
background:${this.theme.primary};color:#fff;
|
|
2147
2118
|
border:none;cursor:pointer;
|
|
@@ -2162,7 +2133,7 @@ class SmartComplyFlow {
|
|
|
2162
2133
|
const btn = document.createElement("button");
|
|
2163
2134
|
btn.textContent = text;
|
|
2164
2135
|
btn.style.cssText = `
|
|
2165
|
-
width:100%;padding:12px;border-radius
|
|
2136
|
+
width:100%;padding:12px;border-radius:${theme_1.RADIUS.md}px;
|
|
2166
2137
|
font-size:14px;font-weight:500;
|
|
2167
2138
|
background:transparent;color:${this.theme.textSecondary};
|
|
2168
2139
|
border:none;cursor:pointer;
|
|
@@ -2300,9 +2271,6 @@ class SmartComplyFlow {
|
|
|
2300
2271
|
const style = document.createElement("style");
|
|
2301
2272
|
style.id = "sc-flow-styles";
|
|
2302
2273
|
style.textContent = `
|
|
2303
|
-
@keyframes sc-spin {
|
|
2304
|
-
to { transform: rotate(360deg); }
|
|
2305
|
-
}
|
|
2306
2274
|
@keyframes sc-pop {
|
|
2307
2275
|
0% { transform: scale(0.8); opacity: 0; }
|
|
2308
2276
|
50% { transform: scale(1.05); }
|