smartcomply-web-sdk 1.0.51 → 1.0.53
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/ActionDetector.d.ts +0 -5
- package/dist/camera/ActionDetector.d.ts.map +1 -1
- package/dist/camera/ActionDetector.js +1 -12
- package/dist/camera/ActionDetector.js.map +1 -1
- package/dist/esm/camera/ActionDetector.d.ts +0 -5
- package/dist/esm/camera/ActionDetector.d.ts.map +1 -1
- package/dist/esm/camera/ActionDetector.js +1 -12
- package/dist/esm/camera/ActionDetector.js.map +1 -1
- package/dist/esm/flow/SmartComplyFlow.js +144 -144
- package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
- package/dist/esm/modules/liveness/LivenessUI.d.ts +10 -2
- package/dist/esm/modules/liveness/LivenessUI.d.ts.map +1 -1
- package/dist/esm/modules/liveness/LivenessUI.js +129 -7
- package/dist/esm/modules/liveness/LivenessUI.js.map +1 -1
- package/dist/esm/modules/liveness/liveness.js +3 -3
- package/dist/esm/modules/liveness/liveness.js.map +1 -1
- package/dist/esm/utils/constants.d.ts +0 -2
- package/dist/esm/utils/constants.d.ts.map +1 -1
- package/dist/esm/utils/constants.js +0 -2
- package/dist/esm/utils/constants.js.map +1 -1
- package/dist/flow/SmartComplyFlow.js +144 -144
- package/dist/flow/SmartComplyFlow.js.map +1 -1
- package/dist/modules/liveness/LivenessUI.d.ts +10 -2
- package/dist/modules/liveness/LivenessUI.d.ts.map +1 -1
- package/dist/modules/liveness/LivenessUI.js +129 -7
- package/dist/modules/liveness/LivenessUI.js.map +1 -1
- package/dist/modules/liveness/liveness.js +3 -3
- package/dist/modules/liveness/liveness.js.map +1 -1
- package/dist/smartcomply.browser.js +206 -107
- package/dist/smartcomply.browser.js.map +3 -3
- package/dist/utils/constants.d.ts +0 -2
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +1 -3
- package/dist/utils/constants.js.map +1 -1
- package/package.json +1 -1
|
@@ -4460,8 +4460,7 @@ var SmartComplySDK = (() => {
|
|
|
4460
4460
|
var BLINK_HOLD_FRAMES = 2;
|
|
4461
4461
|
var YAW_MOTION_THRESHOLD_DEG = 6;
|
|
4462
4462
|
var ActionDetector = class {
|
|
4463
|
-
|
|
4464
|
-
constructor(_requiredActions) {
|
|
4463
|
+
constructor() {
|
|
4465
4464
|
this.blinkHoldCount = 0;
|
|
4466
4465
|
this.blinkDetected = false;
|
|
4467
4466
|
this.motionDetected = false;
|
|
@@ -4498,24 +4497,13 @@ var SmartComplySDK = (() => {
|
|
|
4498
4497
|
faceDetected,
|
|
4499
4498
|
blinkDetected: this.blinkDetected,
|
|
4500
4499
|
motionDetected: this.motionDetected,
|
|
4501
|
-
livenessConfirmed: this.blinkDetected || this.motionDetected
|
|
4502
|
-
progress: 0
|
|
4503
|
-
// caller fills in time-based progress
|
|
4500
|
+
livenessConfirmed: this.blinkDetected || this.motionDetected
|
|
4504
4501
|
};
|
|
4505
4502
|
}
|
|
4506
4503
|
getHeadYaw(matrix) {
|
|
4507
4504
|
if (!matrix || matrix.length < 16) return 0;
|
|
4508
4505
|
return Math.atan2(-matrix[2], matrix[0]) * (180 / Math.PI);
|
|
4509
4506
|
}
|
|
4510
|
-
livenessConfirmed() {
|
|
4511
|
-
return this.blinkDetected || this.motionDetected;
|
|
4512
|
-
}
|
|
4513
|
-
reset() {
|
|
4514
|
-
this.blinkHoldCount = 0;
|
|
4515
|
-
this.blinkDetected = false;
|
|
4516
|
-
this.motionDetected = false;
|
|
4517
|
-
this.baselineYaw = null;
|
|
4518
|
-
}
|
|
4519
4507
|
};
|
|
4520
4508
|
|
|
4521
4509
|
// src/modules/liveness/LivenessUI.ts
|
|
@@ -4533,6 +4521,20 @@ var SmartComplySDK = (() => {
|
|
|
4533
4521
|
0%,100% { opacity:0.3; transform:scale(0.85); }
|
|
4534
4522
|
50% { opacity:1; transform:scale(1); }
|
|
4535
4523
|
}
|
|
4524
|
+
@keyframes sc-scanline-sweep {
|
|
4525
|
+
0% { transform:translateY(-4%); opacity:0; }
|
|
4526
|
+
8% { opacity:0.9; }
|
|
4527
|
+
92% { opacity:0.9; }
|
|
4528
|
+
100% { transform:translateY(104%); opacity:0; }
|
|
4529
|
+
}
|
|
4530
|
+
@keyframes sc-corner-pulse {
|
|
4531
|
+
0%,100% { opacity:0.55; }
|
|
4532
|
+
50% { opacity:1; }
|
|
4533
|
+
}
|
|
4534
|
+
@keyframes sc-oval-breathe {
|
|
4535
|
+
0%,100% { opacity:0.5; }
|
|
4536
|
+
50% { opacity:0.85; }
|
|
4537
|
+
}
|
|
4536
4538
|
`;
|
|
4537
4539
|
document.head.appendChild(s2);
|
|
4538
4540
|
}
|
|
@@ -4542,11 +4544,15 @@ var SmartComplySDK = (() => {
|
|
|
4542
4544
|
this.videoEl = null;
|
|
4543
4545
|
this.instructionEl = null;
|
|
4544
4546
|
this.confidenceRingEl = null;
|
|
4547
|
+
this.bgOvalEl = null;
|
|
4548
|
+
this.guideWrapEl = null;
|
|
4549
|
+
this.scanlineEl = null;
|
|
4545
4550
|
this.overlayEl = null;
|
|
4546
4551
|
this.dotsEl = null;
|
|
4547
4552
|
this.docCaptureRoot = null;
|
|
4548
4553
|
this.scanStartMs = 0;
|
|
4549
4554
|
this.scanDurationMs = 0;
|
|
4555
|
+
this.faceTracked = false;
|
|
4550
4556
|
}
|
|
4551
4557
|
mount(container, challenge) {
|
|
4552
4558
|
injectLivenessKeyframes();
|
|
@@ -4564,41 +4570,110 @@ var SmartComplySDK = (() => {
|
|
|
4564
4570
|
this.videoEl.muted = true;
|
|
4565
4571
|
this.videoEl.style.cssText = `
|
|
4566
4572
|
width:100%;height:100%;display:block;
|
|
4573
|
+
filter:brightness(1.03) contrast(1.03);
|
|
4567
4574
|
transform:scaleX(-1);object-fit:cover;
|
|
4575
|
+
`;
|
|
4576
|
+
const vignette = document.createElement("div");
|
|
4577
|
+
vignette.style.cssText = `
|
|
4578
|
+
position:absolute;inset:0;pointer-events:none;
|
|
4579
|
+
background:radial-gradient(ellipse 34% 44% at 50% 47%, transparent 55%, rgba(0,0,0,0.55) 100%);
|
|
4568
4580
|
`;
|
|
4569
4581
|
const guideWrap = document.createElement("div");
|
|
4570
4582
|
guideWrap.style.cssText = `
|
|
4571
4583
|
position:absolute;top:50%;left:50%;
|
|
4572
4584
|
transform:translate(-50%,-52%);
|
|
4573
4585
|
width:64%;aspect-ratio:140/180;pointer-events:none;
|
|
4586
|
+
filter:drop-shadow(0 0 18px rgba(59,130,246,0.35));
|
|
4587
|
+
transition:filter 0.3s ease;
|
|
4574
4588
|
`;
|
|
4589
|
+
this.guideWrapEl = guideWrap;
|
|
4575
4590
|
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
4576
4591
|
svg.setAttribute("viewBox", "0 0 140 180");
|
|
4577
|
-
svg.style.cssText = "width:100%;height:100%;";
|
|
4592
|
+
svg.style.cssText = "width:100%;height:100%;overflow:visible;";
|
|
4593
|
+
const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
|
|
4594
|
+
const clip = document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
|
|
4595
|
+
clip.setAttribute("id", "sc-oval-clip");
|
|
4596
|
+
const clipOval = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
|
|
4597
|
+
clipOval.setAttribute("cx", "70");
|
|
4598
|
+
clipOval.setAttribute("cy", "90");
|
|
4599
|
+
clipOval.setAttribute("rx", "64");
|
|
4600
|
+
clipOval.setAttribute("ry", "86");
|
|
4601
|
+
clip.appendChild(clipOval);
|
|
4602
|
+
defs.appendChild(clip);
|
|
4603
|
+
svg.appendChild(defs);
|
|
4604
|
+
const trackOval = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
|
|
4605
|
+
trackOval.setAttribute("cx", "70");
|
|
4606
|
+
trackOval.setAttribute("cy", "90");
|
|
4607
|
+
trackOval.setAttribute("rx", "58");
|
|
4608
|
+
trackOval.setAttribute("ry", "80");
|
|
4609
|
+
trackOval.setAttribute("fill", "none");
|
|
4610
|
+
trackOval.setAttribute("stroke", "rgba(255,255,255,0.16)");
|
|
4611
|
+
trackOval.setAttribute("stroke-width", "1");
|
|
4612
|
+
trackOval.setAttribute("stroke-dasharray", "2 5");
|
|
4613
|
+
svg.appendChild(trackOval);
|
|
4578
4614
|
const bgOval = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
|
|
4579
4615
|
bgOval.setAttribute("cx", "70");
|
|
4580
4616
|
bgOval.setAttribute("cy", "90");
|
|
4581
4617
|
bgOval.setAttribute("rx", "64");
|
|
4582
4618
|
bgOval.setAttribute("ry", "86");
|
|
4583
4619
|
bgOval.setAttribute("fill", "none");
|
|
4584
|
-
bgOval.setAttribute("stroke", "rgba(255,255,255,0.
|
|
4585
|
-
bgOval.setAttribute("stroke-width", "
|
|
4620
|
+
bgOval.setAttribute("stroke", "rgba(255,255,255,0.4)");
|
|
4621
|
+
bgOval.setAttribute("stroke-width", "1.5");
|
|
4622
|
+
bgOval.style.cssText = "animation:sc-oval-breathe 2.4s ease-in-out infinite;transition:stroke 0.3s ease;";
|
|
4623
|
+
this.bgOvalEl = bgOval;
|
|
4586
4624
|
const confOval = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
|
|
4587
4625
|
confOval.setAttribute("cx", "70");
|
|
4588
4626
|
confOval.setAttribute("cy", "90");
|
|
4589
4627
|
confOval.setAttribute("rx", "64");
|
|
4590
4628
|
confOval.setAttribute("ry", "86");
|
|
4591
4629
|
confOval.setAttribute("fill", "none");
|
|
4592
|
-
confOval.setAttribute("stroke", "#
|
|
4593
|
-
confOval.setAttribute("stroke-width", "
|
|
4630
|
+
confOval.setAttribute("stroke", "#3b82f6");
|
|
4631
|
+
confOval.setAttribute("stroke-width", "2.5");
|
|
4632
|
+
confOval.setAttribute("stroke-linecap", "round");
|
|
4594
4633
|
const circ = 2 * Math.PI * Math.sqrt((64 * 64 + 86 * 86) / 2);
|
|
4595
4634
|
confOval.setAttribute("stroke-dasharray", `${circ}`);
|
|
4596
4635
|
confOval.setAttribute("stroke-dashoffset", `${circ}`);
|
|
4597
|
-
confOval.style.cssText = "transition:stroke-dashoffset 0.2s linear;transform:rotate(-90deg);transform-origin:70px 90px;";
|
|
4636
|
+
confOval.style.cssText = "transition:stroke-dashoffset 0.2s linear,stroke 0.3s ease;transform:rotate(-90deg);transform-origin:70px 90px;";
|
|
4598
4637
|
this.confidenceRingEl = confOval;
|
|
4638
|
+
const bracketGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
4639
|
+
bracketGroup.setAttribute("stroke", "#3b82f6");
|
|
4640
|
+
bracketGroup.setAttribute("stroke-width", "3");
|
|
4641
|
+
bracketGroup.setAttribute("stroke-linecap", "round");
|
|
4642
|
+
bracketGroup.setAttribute("fill", "none");
|
|
4643
|
+
bracketGroup.style.cssText = "animation:sc-corner-pulse 2s ease-in-out infinite;";
|
|
4644
|
+
const bracketLen = 14;
|
|
4645
|
+
const bx0 = 70 - 64 * 0.74, bx1 = 70 + 64 * 0.74;
|
|
4646
|
+
const by0 = 90 - 86 * 0.82, by1 = 90 + 86 * 0.82;
|
|
4647
|
+
const brackets = [
|
|
4648
|
+
`M${bx0},${by0 + bracketLen} L${bx0},${by0} L${bx0 + bracketLen},${by0}`,
|
|
4649
|
+
`M${bx1 - bracketLen},${by0} L${bx1},${by0} L${bx1},${by0 + bracketLen}`,
|
|
4650
|
+
`M${bx0},${by1 - bracketLen} L${bx0},${by1} L${bx0 + bracketLen},${by1}`,
|
|
4651
|
+
`M${bx1 - bracketLen},${by1} L${bx1},${by1} L${bx1},${by1 - bracketLen}`
|
|
4652
|
+
];
|
|
4653
|
+
for (const d2 of brackets) {
|
|
4654
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
4655
|
+
path.setAttribute("d", d2);
|
|
4656
|
+
bracketGroup.appendChild(path);
|
|
4657
|
+
}
|
|
4599
4658
|
svg.appendChild(bgOval);
|
|
4600
4659
|
svg.appendChild(confOval);
|
|
4660
|
+
svg.appendChild(bracketGroup);
|
|
4601
4661
|
guideWrap.appendChild(svg);
|
|
4662
|
+
const scanlineClipWrap = document.createElement("div");
|
|
4663
|
+
scanlineClipWrap.style.cssText = `
|
|
4664
|
+
position:absolute;inset:0;
|
|
4665
|
+
clip-path:ellipse(45.7% 47.8% at 50% 50%);
|
|
4666
|
+
overflow:hidden;
|
|
4667
|
+
`;
|
|
4668
|
+
const scanline = document.createElement("div");
|
|
4669
|
+
scanline.style.cssText = `
|
|
4670
|
+
position:absolute;left:0;right:0;height:26%;top:0;
|
|
4671
|
+
background:linear-gradient(180deg,transparent 0%,rgba(59,130,246,0.32) 45%,rgba(147,197,253,0.55) 50%,rgba(59,130,246,0.32) 55%,transparent 100%);
|
|
4672
|
+
animation:sc-scanline-sweep 2.6s ease-in-out infinite;
|
|
4673
|
+
`;
|
|
4674
|
+
this.scanlineEl = scanline;
|
|
4675
|
+
scanlineClipWrap.appendChild(scanline);
|
|
4676
|
+
guideWrap.appendChild(scanlineClipWrap);
|
|
4602
4677
|
const camTop = document.createElement("div");
|
|
4603
4678
|
camTop.style.cssText = `
|
|
4604
4679
|
position:absolute;top:0;left:0;right:0;
|
|
@@ -4622,13 +4697,14 @@ var SmartComplySDK = (() => {
|
|
|
4622
4697
|
for (let i2 = 0; i2 < 3; i2++) {
|
|
4623
4698
|
const dot = document.createElement("div");
|
|
4624
4699
|
dot.style.cssText = `
|
|
4625
|
-
width:6px;height:6px;border-radius:50%;background:#
|
|
4700
|
+
width:6px;height:6px;border-radius:50%;background:#3b82f6;
|
|
4626
4701
|
animation:sc-scan-dot 1.1s ease-in-out ${i2 * 0.18}s infinite;
|
|
4627
4702
|
`;
|
|
4628
4703
|
this.dotsEl.appendChild(dot);
|
|
4629
4704
|
}
|
|
4630
4705
|
camBottom.appendChild(this.dotsEl);
|
|
4631
4706
|
this.root.appendChild(this.videoEl);
|
|
4707
|
+
this.root.appendChild(vignette);
|
|
4632
4708
|
this.root.appendChild(guideWrap);
|
|
4633
4709
|
this.root.appendChild(camTop);
|
|
4634
4710
|
this.root.appendChild(camBottom);
|
|
@@ -4662,6 +4738,25 @@ var SmartComplySDK = (() => {
|
|
|
4662
4738
|
this.confidenceRingEl.setAttribute("stroke-dashoffset", `${circ * (1 - pct)}`);
|
|
4663
4739
|
this.confidenceRingEl.setAttribute("stroke", livenessConfirmed ? "#22c55e" : "#3b82f6");
|
|
4664
4740
|
}
|
|
4741
|
+
/**
|
|
4742
|
+
* Reflects whether a face is currently detected in-frame — brightens the
|
|
4743
|
+
* oval guide's glow/brackets when locked on, and dims the scan-line sweep
|
|
4744
|
+
* so the UI visibly distinguishes "searching" from "actively scanning".
|
|
4745
|
+
*/
|
|
4746
|
+
setFaceTracking(tracked) {
|
|
4747
|
+
if (this.faceTracked === tracked) return;
|
|
4748
|
+
this.faceTracked = tracked;
|
|
4749
|
+
if (this.guideWrapEl) {
|
|
4750
|
+
this.guideWrapEl.style.filter = tracked ? "drop-shadow(0 0 22px rgba(34,197,94,0.45))" : "drop-shadow(0 0 18px rgba(59,130,246,0.35))";
|
|
4751
|
+
}
|
|
4752
|
+
if (this.bgOvalEl) {
|
|
4753
|
+
this.bgOvalEl.setAttribute("stroke", tracked ? "rgba(74,222,128,0.55)" : "rgba(255,255,255,0.4)");
|
|
4754
|
+
}
|
|
4755
|
+
if (this.scanlineEl) {
|
|
4756
|
+
this.scanlineEl.style.animationPlayState = tracked ? "running" : "paused";
|
|
4757
|
+
this.scanlineEl.style.opacity = tracked ? "1" : "0.4";
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4665
4760
|
updateInstruction(text) {
|
|
4666
4761
|
if (this.instructionEl) this.instructionEl.textContent = text;
|
|
4667
4762
|
}
|
|
@@ -4803,6 +4898,10 @@ var SmartComplySDK = (() => {
|
|
|
4803
4898
|
this.confidenceRingEl = null;
|
|
4804
4899
|
this.overlayEl = null;
|
|
4805
4900
|
this.dotsEl = null;
|
|
4901
|
+
this.bgOvalEl = null;
|
|
4902
|
+
this.guideWrapEl = null;
|
|
4903
|
+
this.scanlineEl = null;
|
|
4904
|
+
this.faceTracked = false;
|
|
4806
4905
|
}
|
|
4807
4906
|
};
|
|
4808
4907
|
|
|
@@ -4970,7 +5069,7 @@ var SmartComplySDK = (() => {
|
|
|
4970
5069
|
tempVideo.muted = true;
|
|
4971
5070
|
tempVideo.playsInline = true;
|
|
4972
5071
|
await tempVideo.play();
|
|
4973
|
-
ui2.mount(container, {
|
|
5072
|
+
ui2.mount(container, { time_limit_seconds: 0, instruction: "Centre your face in the oval" });
|
|
4974
5073
|
const uiVideo = ui2.getVideoElement();
|
|
4975
5074
|
if (uiVideo) {
|
|
4976
5075
|
uiVideo.srcObject = stream;
|
|
@@ -4983,7 +5082,6 @@ var SmartComplySDK = (() => {
|
|
|
4983
5082
|
ui2.updateInstruction("Centre your face in the oval");
|
|
4984
5083
|
const videoForDetection = uiVideo || tempVideo;
|
|
4985
5084
|
await new Promise((resolve) => {
|
|
4986
|
-
let attempts = 0;
|
|
4987
5085
|
let stableFrames = 0;
|
|
4988
5086
|
let missedFrames = 0;
|
|
4989
5087
|
const STABLE_REQUIRED = 4;
|
|
@@ -4997,6 +5095,7 @@ var SmartComplySDK = (() => {
|
|
|
4997
5095
|
}
|
|
4998
5096
|
if (videoForDetection.readyState >= 2) {
|
|
4999
5097
|
const detection = faceEngine.detect(videoForDetection, performance.now());
|
|
5098
|
+
ui2.setFaceTracking(detection.faceDetected);
|
|
5000
5099
|
if (detection.faceDetected) {
|
|
5001
5100
|
stableFrames++;
|
|
5002
5101
|
missedFrames = 0;
|
|
@@ -5045,7 +5144,6 @@ var SmartComplySDK = (() => {
|
|
|
5045
5144
|
tempVideo.srcObject = null;
|
|
5046
5145
|
tempVideo.remove();
|
|
5047
5146
|
const uiChallenge = {
|
|
5048
|
-
actions: entry.challenge_actions,
|
|
5049
5147
|
time_limit_seconds: LIVENESS_TIME_LIMIT_SECONDS,
|
|
5050
5148
|
instruction: "Blink and look around naturally"
|
|
5051
5149
|
};
|
|
@@ -5072,6 +5170,7 @@ var SmartComplySDK = (() => {
|
|
|
5072
5170
|
const detection = faceEngine.detect(videoEl, performance.now());
|
|
5073
5171
|
const scan = actionDetector.check(detection);
|
|
5074
5172
|
ui2.updateScanProgress(scan.livenessConfirmed);
|
|
5173
|
+
ui2.setFaceTracking(detection.faceDetected);
|
|
5075
5174
|
if (!detection.faceDetected) {
|
|
5076
5175
|
ui2.updateInstruction("Move your face into the oval");
|
|
5077
5176
|
} else {
|
|
@@ -6347,13 +6446,13 @@ var SmartComplySDK = (() => {
|
|
|
6347
6446
|
|
|
6348
6447
|
// src/flow/SmartComplyFlow.ts
|
|
6349
6448
|
var COUNTRY_LABELS = {
|
|
6350
|
-
nigeria: "
|
|
6351
|
-
global: "
|
|
6352
|
-
ghana: "
|
|
6353
|
-
kenya: "
|
|
6354
|
-
south_africa: "
|
|
6355
|
-
united_states: "
|
|
6356
|
-
united_kingdom: "
|
|
6449
|
+
nigeria: "🇳🇬 Nigeria",
|
|
6450
|
+
global: "🌍 Other Countries",
|
|
6451
|
+
ghana: "🇬🇭 Ghana",
|
|
6452
|
+
kenya: "🇰🇪 Kenya",
|
|
6453
|
+
south_africa: "🇿🇦 South Africa",
|
|
6454
|
+
united_states: "🇺🇸 United States",
|
|
6455
|
+
united_kingdom: "🇬🇧 United Kingdom"
|
|
6357
6456
|
};
|
|
6358
6457
|
function isUploadFieldType(type) {
|
|
6359
6458
|
return type === "upload" || type === "image" || type === "file";
|
|
@@ -6367,37 +6466,37 @@ var SmartComplySDK = (() => {
|
|
|
6367
6466
|
return t2.includes("voter") || t2.includes("driver") || t2.includes("license") || t2.includes("national id") || t2.includes("national id card");
|
|
6368
6467
|
};
|
|
6369
6468
|
if (u2.includes("BVN") || u2.includes("BANK VERIFICATION")) {
|
|
6370
|
-
return { icon: "
|
|
6469
|
+
return { icon: "🏦", desc: "Enter your 11-digit Bank Verification Number (BVN)", requiresBack: false };
|
|
6371
6470
|
}
|
|
6372
6471
|
if (u2.includes("NIN") || u2.includes("NATIONAL IDENTITY NUMBER")) {
|
|
6373
|
-
return { icon: "
|
|
6472
|
+
return { icon: "🆔", desc: "Enter your 11-digit National Identification Number (NIN)", requiresBack: false };
|
|
6374
6473
|
}
|
|
6375
6474
|
if (u2.includes("GHANA")) {
|
|
6376
|
-
if (isDocumentFlow) return { icon: "
|
|
6377
|
-
return { icon: "
|
|
6475
|
+
if (isDocumentFlow) return { icon: "🪪", desc: "Capture or upload your Ghana Card", requiresBack: true };
|
|
6476
|
+
return { icon: "🪪", desc: "Enter your Ghana Card number", requiresBack: false };
|
|
6378
6477
|
}
|
|
6379
6478
|
if (u2.includes("SSNIT"))
|
|
6380
|
-
return { icon: "
|
|
6479
|
+
return { icon: "🏛️", desc: "Enter your SSNIT number", requiresBack: false };
|
|
6381
6480
|
if (u2.includes("KENYA") || u2.includes("NATIONAL") && u2.includes("KENYA"))
|
|
6382
|
-
return { icon: "
|
|
6481
|
+
return { icon: "🆔", desc: "Enter your Kenya National ID number", requiresBack: false };
|
|
6383
6482
|
if (u2.includes("TIN") || u2.includes("TAX IDENTIFICATION"))
|
|
6384
|
-
return { icon: "
|
|
6483
|
+
return { icon: "🧾", desc: "Enter your Tax Identification Number (TIN)", requiresBack: false };
|
|
6385
6484
|
if (u2.includes("CAC") || u2.includes("CORPORATE AFFAIRS") || u2.includes("COMPANY"))
|
|
6386
|
-
return { icon: "
|
|
6485
|
+
return { icon: "🏢", desc: advanced ? "Enter RC number, company name & type" : "Enter your company registration number", requiresBack: false };
|
|
6387
6486
|
if (u2.includes("VOTER") || u2.includes("PVC")) {
|
|
6388
6487
|
const requiresBack = requiresBackSide(typeName);
|
|
6389
6488
|
return {
|
|
6390
|
-
icon: "
|
|
6489
|
+
icon: "🗳️",
|
|
6391
6490
|
desc: isDocumentFlow ? `Capture or upload your voter's card${requiresBack ? " (front & back)" : ""}` : "Enter your voter ID number",
|
|
6392
6491
|
requiresBack: isDocumentFlow ? requiresBack : false
|
|
6393
6492
|
};
|
|
6394
6493
|
}
|
|
6395
6494
|
if (u2.includes("PASSPORT"))
|
|
6396
|
-
return { icon: "
|
|
6495
|
+
return { icon: "📘", desc: isDocumentFlow ? "Capture or upload your passport" : "Enter your passport number", requiresBack: false };
|
|
6397
6496
|
if (u2.includes("DRIVER") || u2.includes("LICENSE") || u2.includes("LICENCE")) {
|
|
6398
6497
|
const requiresBack = requiresBackSide(typeName);
|
|
6399
6498
|
return {
|
|
6400
|
-
icon: "
|
|
6499
|
+
icon: "🚗",
|
|
6401
6500
|
desc: isDocumentFlow ? `Capture or upload your driver's license${requiresBack ? " (front & back)" : ""}` : "Enter your driver's license number",
|
|
6402
6501
|
requiresBack: isDocumentFlow ? requiresBack : false
|
|
6403
6502
|
};
|
|
@@ -6405,15 +6504,15 @@ var SmartComplySDK = (() => {
|
|
|
6405
6504
|
if (u2.includes("NATIONAL ID") || u2.includes("NATIONAL") && u2.includes("CARD")) {
|
|
6406
6505
|
const requiresBack = requiresBackSide(typeName);
|
|
6407
6506
|
return {
|
|
6408
|
-
icon: "
|
|
6507
|
+
icon: "🪪",
|
|
6409
6508
|
desc: isDocumentFlow ? `Capture or upload your ID card${requiresBack ? " (front & back)" : ""}` : "Enter your National ID number",
|
|
6410
6509
|
requiresBack: isDocumentFlow ? requiresBack : false
|
|
6411
6510
|
};
|
|
6412
6511
|
}
|
|
6413
6512
|
if (u2.includes("LIVENESS") || u2.includes("FACE COMPARISON") || u2.includes("FACE MATCH"))
|
|
6414
|
-
return { icon: "
|
|
6513
|
+
return { icon: "🤳", desc: "We'll capture a short selfie video to verify you", requiresBack: false };
|
|
6415
6514
|
return {
|
|
6416
|
-
icon: isDocumentFlow ? "
|
|
6515
|
+
icon: isDocumentFlow ? "📄" : "🆔",
|
|
6417
6516
|
desc: isDocumentFlow ? "Capture or upload your document" : "Enter your ID number",
|
|
6418
6517
|
requiresBack: false
|
|
6419
6518
|
};
|
|
@@ -6551,7 +6650,7 @@ var SmartComplySDK = (() => {
|
|
|
6551
6650
|
this.livenessEntryId = null;
|
|
6552
6651
|
this.isDestroyed = false;
|
|
6553
6652
|
this.headerBackBtn = null;
|
|
6554
|
-
// Retry safety
|
|
6653
|
+
// Retry safety — max 3 confirmation rejections or liveness failures per session
|
|
6555
6654
|
this._confirmRetries = 0;
|
|
6556
6655
|
this._livenessFailures = 0;
|
|
6557
6656
|
// IVS result stored for confirm_identity screen
|
|
@@ -6566,9 +6665,9 @@ var SmartComplySDK = (() => {
|
|
|
6566
6665
|
this._ocrExpirySoon = false;
|
|
6567
6666
|
// Camera pre-warm stream (created during confirmation screen, used in liveness)
|
|
6568
6667
|
this._prewarmedStream = null;
|
|
6569
|
-
// OCR gate poll timer
|
|
6668
|
+
// OCR gate poll timer — stored so it can be cancelled on navigation or close
|
|
6570
6669
|
this._ocrPollTimer = null;
|
|
6571
|
-
// UI timeout from _startStatusPolling
|
|
6670
|
+
// UI timeout from _startStatusPolling — stored so close() can cancel it
|
|
6572
6671
|
this._uiTimeoutId = null;
|
|
6573
6672
|
// Session expiry
|
|
6574
6673
|
this.sessionExpiryTimer = null;
|
|
@@ -6643,9 +6742,9 @@ var SmartComplySDK = (() => {
|
|
|
6643
6742
|
}
|
|
6644
6743
|
this.options.onClose?.();
|
|
6645
6744
|
}
|
|
6646
|
-
//
|
|
6745
|
+
// ─────────────────────────────────────────────────────────────────
|
|
6647
6746
|
// Initialization
|
|
6648
|
-
//
|
|
6747
|
+
// ─────────────────────────────────────────────────────────────────
|
|
6649
6748
|
mount() {
|
|
6650
6749
|
this.injectStyles();
|
|
6651
6750
|
this.overlay = document.createElement("div");
|
|
@@ -6730,9 +6829,9 @@ var SmartComplySDK = (() => {
|
|
|
6730
6829
|
this.showErrorStep(err.message || "Failed to initialize. Please try again.");
|
|
6731
6830
|
}
|
|
6732
6831
|
}
|
|
6733
|
-
//
|
|
6832
|
+
// ─────────────────────────────────────────────────────────────────
|
|
6734
6833
|
// Step rendering
|
|
6735
|
-
//
|
|
6834
|
+
// ─────────────────────────────────────────────────────────────────
|
|
6736
6835
|
showStep(step) {
|
|
6737
6836
|
this.currentStep = step;
|
|
6738
6837
|
if (!this.contentArea) return;
|
|
@@ -6807,7 +6906,7 @@ var SmartComplySDK = (() => {
|
|
|
6807
6906
|
wrapper.style.transform = "translateX(0)";
|
|
6808
6907
|
});
|
|
6809
6908
|
}
|
|
6810
|
-
//
|
|
6909
|
+
// ── Loading ─────────────────────────────────────────────────────
|
|
6811
6910
|
renderLoading(container) {
|
|
6812
6911
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px;gap:16px;";
|
|
6813
6912
|
const spinnerWrap = document.createElement("div");
|
|
@@ -6838,7 +6937,7 @@ var SmartComplySDK = (() => {
|
|
|
6838
6937
|
sub.textContent = "Connecting to the verification service...";
|
|
6839
6938
|
container.appendChild(sub);
|
|
6840
6939
|
}
|
|
6841
|
-
//
|
|
6940
|
+
// ── Welcome ────────────────────────────────────────────────────
|
|
6842
6941
|
renderWelcome(container) {
|
|
6843
6942
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;";
|
|
6844
6943
|
const isDocFlow = this.isDocumentFlow();
|
|
@@ -6852,7 +6951,7 @@ var SmartComplySDK = (() => {
|
|
|
6852
6951
|
background:linear-gradient(135deg,${this.theme.primary}22,${this.theme.primaryGlow});
|
|
6853
6952
|
border:1.5px solid ${this.theme.primary}33;
|
|
6854
6953
|
`;
|
|
6855
|
-
iconWrap.textContent = isDocFlow ? "
|
|
6954
|
+
iconWrap.textContent = isDocFlow ? "🪪" : "🛡️";
|
|
6856
6955
|
topRow.appendChild(iconWrap);
|
|
6857
6956
|
const badge = document.createElement("div");
|
|
6858
6957
|
badge.style.cssText = `
|
|
@@ -6863,7 +6962,7 @@ var SmartComplySDK = (() => {
|
|
|
6863
6962
|
color:${this.theme.primary};
|
|
6864
6963
|
border:1px solid ${this.theme.primary}30;
|
|
6865
6964
|
`;
|
|
6866
|
-
badge.textContent = isDocFlow ? "
|
|
6965
|
+
badge.textContent = isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
|
|
6867
6966
|
topRow.appendChild(badge);
|
|
6868
6967
|
container.appendChild(topRow);
|
|
6869
6968
|
const titleWrap = document.createElement("div");
|
|
@@ -6885,13 +6984,13 @@ var SmartComplySDK = (() => {
|
|
|
6885
6984
|
titleWrap.appendChild(desc);
|
|
6886
6985
|
container.appendChild(titleWrap);
|
|
6887
6986
|
const steps = isDocFlow ? [
|
|
6888
|
-
{ icon: "
|
|
6889
|
-
{ icon: "
|
|
6890
|
-
{ icon: "
|
|
6987
|
+
{ icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
|
|
6988
|
+
{ icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
|
|
6989
|
+
{ icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" }
|
|
6891
6990
|
] : [
|
|
6892
|
-
{ icon: "
|
|
6893
|
-
{ icon: "
|
|
6894
|
-
{ icon: "
|
|
6991
|
+
{ icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
|
|
6992
|
+
{ icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
|
|
6993
|
+
{ icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" }
|
|
6895
6994
|
];
|
|
6896
6995
|
const stepsWrap = document.createElement("div");
|
|
6897
6996
|
stepsWrap.style.cssText = `
|
|
@@ -6931,7 +7030,7 @@ var SmartComplySDK = (() => {
|
|
|
6931
7030
|
stepsWrap.appendChild(row);
|
|
6932
7031
|
});
|
|
6933
7032
|
container.appendChild(stepsWrap);
|
|
6934
|
-
const btn = this.createPrimaryButton("Get Started
|
|
7033
|
+
const btn = this.createPrimaryButton("Get Started →");
|
|
6935
7034
|
btn.style.cssText += "margin-top:2px;";
|
|
6936
7035
|
btn.addEventListener("click", () => this.showStep("country"));
|
|
6937
7036
|
container.appendChild(btn);
|
|
@@ -6940,10 +7039,10 @@ var SmartComplySDK = (() => {
|
|
|
6940
7039
|
display:flex;align-items:center;gap:6px;
|
|
6941
7040
|
color:${this.theme.textMuted};font-size:10.5px;
|
|
6942
7041
|
`;
|
|
6943
|
-
trust.textContent = "
|
|
7042
|
+
trust.textContent = "🔒 End-to-end encrypted";
|
|
6944
7043
|
container.appendChild(trust);
|
|
6945
7044
|
}
|
|
6946
|
-
//
|
|
7045
|
+
// ── Country Select ──────────────────────────────────────────────
|
|
6947
7046
|
renderCountrySelect(container) {
|
|
6948
7047
|
container.style.cssText += "display:flex;flex-direction:column;gap:14px;";
|
|
6949
7048
|
const channels = this.sdkConfig?.channels || {};
|
|
@@ -6971,7 +7070,7 @@ var SmartComplySDK = (() => {
|
|
|
6971
7070
|
container.appendChild(card);
|
|
6972
7071
|
}
|
|
6973
7072
|
}
|
|
6974
|
-
//
|
|
7073
|
+
// ── ID Type Select ──────────────────────────────────────────────
|
|
6975
7074
|
renderIdTypeSelect(container) {
|
|
6976
7075
|
container.style.cssText += "display:flex;flex-direction:column;gap:14px;";
|
|
6977
7076
|
const globalDocFlow = this.isDocumentFlow();
|
|
@@ -6993,7 +7092,7 @@ var SmartComplySDK = (() => {
|
|
|
6993
7092
|
const requiresBack = requiresBackFromBackend ?? info.requiresBack;
|
|
6994
7093
|
let subtitle2 = info.desc;
|
|
6995
7094
|
if (requiresBack && isThisDocFlow) {
|
|
6996
|
-
subtitle2 += "
|
|
7095
|
+
subtitle2 += " ⚠️ Both sides required";
|
|
6997
7096
|
}
|
|
6998
7097
|
const displayName = typeName.replace(/\s*with\s+face\s*/gi, " ").replace(/\s*\(NIN\)\s*/gi, " ").replace(/\s*\(BVN\)\s*/gi, " ").replace(/\s{2,}/g, " ").trim();
|
|
6999
7098
|
const card = this.createOptionCard(
|
|
@@ -7026,7 +7125,7 @@ var SmartComplySDK = (() => {
|
|
|
7026
7125
|
container.appendChild(card);
|
|
7027
7126
|
}
|
|
7028
7127
|
}
|
|
7029
|
-
//
|
|
7128
|
+
// ── ID Input (data verification — dynamic fields) ─────────────
|
|
7030
7129
|
renderIdInput(container) {
|
|
7031
7130
|
container.style.cssText += "display:flex;flex-direction:column;gap:14px;";
|
|
7032
7131
|
const dataFields = this.selectedChannelFields.filter((f2) => f2.type !== "upload");
|
|
@@ -7056,13 +7155,13 @@ var SmartComplySDK = (() => {
|
|
|
7056
7155
|
{ match: "BVN", rule: { minLen: 11, maxLen: 11, numeric: true, hint: "BVN must be exactly 11 digits" } },
|
|
7057
7156
|
{ match: "NIN", rule: { minLen: 11, maxLen: 11, numeric: true, hint: "NIN must be exactly 11 digits" } },
|
|
7058
7157
|
{ match: "NATIONAL IDENTITY", rule: { minLen: 11, maxLen: 11, numeric: true, hint: "NIN must be exactly 11 digits" } },
|
|
7059
|
-
{ match: "PASSPORT", rule: { minLen: 6, maxLen: 20, alphanumeric: true, hint: "Passport number must be 6
|
|
7060
|
-
{ match: "DRIVER", rule: { minLen: 3, maxLen: 30, alphanumeric: true, hint: "Licence number must be 3
|
|
7061
|
-
{ match: "VOTER", rule: { minLen: 6, maxLen: 30, alphanumeric: true, hint: "Voter ID must be 6
|
|
7062
|
-
{ match: "GHANA", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "Ghana Card number must be 8
|
|
7063
|
-
{ match: "SSNIT", rule: { minLen: 7, maxLen: 15, alphanumeric: true, hint: "SSNIT number must be 7
|
|
7064
|
-
{ match: "TIN", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "TIN must be 8
|
|
7065
|
-
{ match: "KRA", rule: { minLen: 10, maxLen: 12, alphanumeric: true, hint: "KRA PIN must be 10
|
|
7158
|
+
{ match: "PASSPORT", rule: { minLen: 6, maxLen: 20, alphanumeric: true, hint: "Passport number must be 6–20 alphanumeric characters" } },
|
|
7159
|
+
{ match: "DRIVER", rule: { minLen: 3, maxLen: 30, alphanumeric: true, hint: "Licence number must be 3–30 alphanumeric characters" } },
|
|
7160
|
+
{ match: "VOTER", rule: { minLen: 6, maxLen: 30, alphanumeric: true, hint: "Voter ID must be 6–30 alphanumeric characters" } },
|
|
7161
|
+
{ match: "GHANA", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "Ghana Card number must be 8–20 alphanumeric characters" } },
|
|
7162
|
+
{ match: "SSNIT", rule: { minLen: 7, maxLen: 15, alphanumeric: true, hint: "SSNIT number must be 7–15 alphanumeric characters" } },
|
|
7163
|
+
{ match: "TIN", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "TIN must be 8–20 characters" } },
|
|
7164
|
+
{ match: "KRA", rule: { minLen: 10, maxLen: 12, alphanumeric: true, hint: "KRA PIN must be 10–12 characters" } }
|
|
7066
7165
|
];
|
|
7067
7166
|
function getFieldRule(label) {
|
|
7068
7167
|
const upper = label.toUpperCase();
|
|
@@ -7302,7 +7401,7 @@ var SmartComplySDK = (() => {
|
|
|
7302
7401
|
setTimeout(() => firstInput.focus(), 350);
|
|
7303
7402
|
}
|
|
7304
7403
|
}
|
|
7305
|
-
//
|
|
7404
|
+
// ── Document Capture ────────────────────────────────────────────
|
|
7306
7405
|
renderDocumentCapture(container) {
|
|
7307
7406
|
container.style.cssText += "display:flex;flex-direction:column;gap:14px;";
|
|
7308
7407
|
const rawName = this.selectedIdTypeName || this.selectedIdType || "your document";
|
|
@@ -7338,7 +7437,7 @@ var SmartComplySDK = (() => {
|
|
|
7338
7437
|
this.showErrorStep(err.message || "Document capture failed. Please try again.");
|
|
7339
7438
|
});
|
|
7340
7439
|
}
|
|
7341
|
-
//
|
|
7440
|
+
// ── W3: Identity Confirmation (data verification) ───────────────
|
|
7342
7441
|
renderConfirmIdentity(container) {
|
|
7343
7442
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:16px;padding:8px 0;";
|
|
7344
7443
|
if (this._confirmRetries >= _SmartComplyFlow.MAX_RETRIES) {
|
|
@@ -7348,7 +7447,7 @@ var SmartComplySDK = (() => {
|
|
|
7348
7447
|
this._prewarmCamera();
|
|
7349
7448
|
const iconWrap = document.createElement("div");
|
|
7350
7449
|
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;font-size:28px;`;
|
|
7351
|
-
iconWrap.textContent = "
|
|
7450
|
+
iconWrap.textContent = "🛡️";
|
|
7352
7451
|
container.appendChild(iconWrap);
|
|
7353
7452
|
const title = document.createElement("h2");
|
|
7354
7453
|
title.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
|
|
@@ -7385,7 +7484,7 @@ var SmartComplySDK = (() => {
|
|
|
7385
7484
|
sub.textContent = "Your details have been confirmed. Please continue to the face check.";
|
|
7386
7485
|
container.appendChild(sub);
|
|
7387
7486
|
}
|
|
7388
|
-
const yesBtn = this.createPrimaryButton("Yes, that's me
|
|
7487
|
+
const yesBtn = this.createPrimaryButton("Yes, that's me — continue");
|
|
7389
7488
|
yesBtn.addEventListener("click", () => {
|
|
7390
7489
|
this._confirmRetries = 0;
|
|
7391
7490
|
this.showStep("liveness");
|
|
@@ -7402,7 +7501,7 @@ var SmartComplySDK = (() => {
|
|
|
7402
7501
|
});
|
|
7403
7502
|
container.appendChild(noBtn);
|
|
7404
7503
|
}
|
|
7405
|
-
//
|
|
7504
|
+
// ── W4: Document Confirmation (document verification) ────────────
|
|
7406
7505
|
renderDocumentConfirm(container) {
|
|
7407
7506
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:8px 0;";
|
|
7408
7507
|
if (this._confirmRetries >= _SmartComplyFlow.MAX_RETRIES) {
|
|
@@ -7412,7 +7511,7 @@ var SmartComplySDK = (() => {
|
|
|
7412
7511
|
this._prewarmCamera();
|
|
7413
7512
|
const iconWrap = document.createElement("div");
|
|
7414
7513
|
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;font-size:28px;`;
|
|
7415
|
-
iconWrap.textContent = "
|
|
7514
|
+
iconWrap.textContent = "📄";
|
|
7416
7515
|
container.appendChild(iconWrap);
|
|
7417
7516
|
const title = document.createElement("h2");
|
|
7418
7517
|
title.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
|
|
@@ -7435,7 +7534,7 @@ var SmartComplySDK = (() => {
|
|
|
7435
7534
|
if (this._ocrExpirySoon && !this._ocrIsExpired) {
|
|
7436
7535
|
const warn = document.createElement("div");
|
|
7437
7536
|
warn.style.cssText = `width:100%;padding:10px 14px;border-radius:10px;background:${this.theme.warning}18;border:1px solid ${this.theme.warning}40;color:${this.theme.warning};font-size:12px;text-align:left;line-height:1.5;`;
|
|
7438
|
-
warn.textContent = "
|
|
7537
|
+
warn.textContent = "⚠️ Your document expires soon. Some services may not accept it, but you can still continue.";
|
|
7439
7538
|
container.appendChild(warn);
|
|
7440
7539
|
}
|
|
7441
7540
|
const card = document.createElement("div");
|
|
@@ -7489,7 +7588,7 @@ var SmartComplySDK = (() => {
|
|
|
7489
7588
|
});
|
|
7490
7589
|
container.appendChild(noBtn);
|
|
7491
7590
|
}
|
|
7492
|
-
//
|
|
7591
|
+
// ── W6+W7+W8: OCR Gate (document verification) ───────────────────
|
|
7493
7592
|
renderOcrGate(container) {
|
|
7494
7593
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;gap:14px;padding:20px 0;text-align:center;";
|
|
7495
7594
|
const spinnerWrap = document.createElement("div");
|
|
@@ -7498,18 +7597,18 @@ var SmartComplySDK = (() => {
|
|
|
7498
7597
|
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;`;
|
|
7499
7598
|
const centre = document.createElement("div");
|
|
7500
7599
|
centre.style.cssText = "position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;";
|
|
7501
|
-
centre.textContent = "
|
|
7600
|
+
centre.textContent = "📄";
|
|
7502
7601
|
spinnerWrap.appendChild(ring);
|
|
7503
7602
|
spinnerWrap.appendChild(centre);
|
|
7504
7603
|
container.appendChild(spinnerWrap);
|
|
7505
7604
|
const statusEl = document.createElement("div");
|
|
7506
7605
|
statusEl.setAttribute("aria-live", "polite");
|
|
7507
7606
|
statusEl.style.cssText = `color:${this.theme.text};font-size:15px;font-weight:600;`;
|
|
7508
|
-
statusEl.textContent = "Reading your document
|
|
7607
|
+
statusEl.textContent = "Reading your document…";
|
|
7509
7608
|
container.appendChild(statusEl);
|
|
7510
7609
|
const subEl = document.createElement("div");
|
|
7511
7610
|
subEl.style.cssText = `color:${this.theme.textSecondary};font-size:12px;max-width:260px;line-height:1.5;`;
|
|
7512
|
-
subEl.textContent = "This usually takes 5
|
|
7611
|
+
subEl.textContent = "This usually takes 5–15 seconds. Please wait.";
|
|
7513
7612
|
container.appendChild(subEl);
|
|
7514
7613
|
if (!this.livenessEntryId) {
|
|
7515
7614
|
this.showErrorStep("Document upload failed. Please try again.");
|
|
@@ -7554,8 +7653,8 @@ var SmartComplySDK = (() => {
|
|
|
7554
7653
|
if (polls < MAX_POLLS && !this.isDestroyed) {
|
|
7555
7654
|
this._ocrPollTimer = setTimeout(poll, 2e3);
|
|
7556
7655
|
} else if (!this.isDestroyed) {
|
|
7557
|
-
statusEl.textContent = "Taking longer than usual
|
|
7558
|
-
subEl.textContent = "We'll continue
|
|
7656
|
+
statusEl.textContent = "Taking longer than usual…";
|
|
7657
|
+
subEl.textContent = "We'll continue — you can confirm your details on the next screen.";
|
|
7559
7658
|
this._ocrPollTimer = setTimeout(() => {
|
|
7560
7659
|
if (!this.isDestroyed) this.showStep("document_confirm");
|
|
7561
7660
|
}, 2e3);
|
|
@@ -7574,7 +7673,7 @@ var SmartComplySDK = (() => {
|
|
|
7574
7673
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:20px 0;";
|
|
7575
7674
|
const icon = document.createElement("div");
|
|
7576
7675
|
icon.style.cssText = `width:72px;height:72px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:28px;`;
|
|
7577
|
-
icon.textContent = "
|
|
7676
|
+
icon.textContent = "📅";
|
|
7578
7677
|
container.appendChild(icon);
|
|
7579
7678
|
const t2 = document.createElement("h2");
|
|
7580
7679
|
t2.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
|
|
@@ -7603,7 +7702,7 @@ var SmartComplySDK = (() => {
|
|
|
7603
7702
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:20px 0;";
|
|
7604
7703
|
const icon = document.createElement("div");
|
|
7605
7704
|
icon.style.cssText = `width:72px;height:72px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:28px;`;
|
|
7606
|
-
icon.textContent = "
|
|
7705
|
+
icon.textContent = "🔍";
|
|
7607
7706
|
container.appendChild(icon);
|
|
7608
7707
|
const t2 = document.createElement("h2");
|
|
7609
7708
|
t2.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
|
|
@@ -7623,7 +7722,7 @@ var SmartComplySDK = (() => {
|
|
|
7623
7722
|
});
|
|
7624
7723
|
container.appendChild(retryBtn);
|
|
7625
7724
|
}
|
|
7626
|
-
//
|
|
7725
|
+
// ── W11: You're all done (end-user final screen) ─────────────────
|
|
7627
7726
|
renderDone(container) {
|
|
7628
7727
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:16px;padding:24px 0;";
|
|
7629
7728
|
container.setAttribute("role", "status");
|
|
@@ -7636,7 +7735,7 @@ var SmartComplySDK = (() => {
|
|
|
7636
7735
|
});
|
|
7637
7736
|
const iconWrap = document.createElement("div");
|
|
7638
7737
|
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;font-size:36px;font-weight:700;color:${this.theme.success};animation:sc-pop 0.4s ease;`;
|
|
7639
|
-
iconWrap.textContent = "
|
|
7738
|
+
iconWrap.textContent = "✓";
|
|
7640
7739
|
container.appendChild(iconWrap);
|
|
7641
7740
|
const title = document.createElement("h2");
|
|
7642
7741
|
title.style.cssText = `color:${this.theme.text};font-size:22px;font-weight:700;margin:0;`;
|
|
@@ -7648,7 +7747,7 @@ var SmartComplySDK = (() => {
|
|
|
7648
7747
|
container.appendChild(desc);
|
|
7649
7748
|
const info = document.createElement("div");
|
|
7650
7749
|
info.style.cssText = `color:${this.theme.textMuted};font-size:11px;display:flex;align-items:center;gap:4px;`;
|
|
7651
|
-
info.textContent = "
|
|
7750
|
+
info.textContent = "🔒 Your data is encrypted and secure";
|
|
7652
7751
|
container.appendChild(info);
|
|
7653
7752
|
const doneBtn = this.createPrimaryButton("Close");
|
|
7654
7753
|
doneBtn.addEventListener("click", () => {
|
|
@@ -7656,12 +7755,12 @@ var SmartComplySDK = (() => {
|
|
|
7656
7755
|
});
|
|
7657
7756
|
container.appendChild(doneBtn);
|
|
7658
7757
|
}
|
|
7659
|
-
//
|
|
7758
|
+
// ── W14: Retry limit reached ─────────────────────────────────────
|
|
7660
7759
|
_renderRetryLimitReached(container) {
|
|
7661
7760
|
container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:24px 0;";
|
|
7662
7761
|
const icon = document.createElement("div");
|
|
7663
7762
|
icon.style.cssText = `width:72px;height:72px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:28px;`;
|
|
7664
|
-
icon.textContent = "
|
|
7763
|
+
icon.textContent = "⚠️";
|
|
7665
7764
|
container.appendChild(icon);
|
|
7666
7765
|
const t2 = document.createElement("h2");
|
|
7667
7766
|
t2.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
|
|
@@ -7678,7 +7777,7 @@ var SmartComplySDK = (() => {
|
|
|
7678
7777
|
});
|
|
7679
7778
|
container.appendChild(closeBtn);
|
|
7680
7779
|
}
|
|
7681
|
-
//
|
|
7780
|
+
// ── W13: Camera pre-warm ─────────────────────────────────────────
|
|
7682
7781
|
_prewarmCamera() {
|
|
7683
7782
|
if (this._prewarmedStream || this.isDestroyed) return;
|
|
7684
7783
|
navigator.mediaDevices?.getUserMedia?.({ video: { facingMode: "user" } }).then((stream) => {
|
|
@@ -7717,7 +7816,7 @@ var SmartComplySDK = (() => {
|
|
|
7717
7816
|
<div style="display:flex;flex-direction:column;align-items:center;gap:14px;padding:28px 20px;">
|
|
7718
7817
|
<div style="position:relative;width:52px;height:52px;">
|
|
7719
7818
|
<div style="position:absolute;inset:0;border-radius:50%;border:3px solid ${this.theme.border};border-top-color:${this.theme.primary};animation:sc-spin 0.8s linear infinite;"></div>
|
|
7720
|
-
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;"
|
|
7819
|
+
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔍</div>
|
|
7721
7820
|
</div>
|
|
7722
7821
|
<div style="color:${this.theme.text};font-size:14px;font-weight:600;">Scanning document...</div>
|
|
7723
7822
|
<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>
|
|
@@ -7775,7 +7874,7 @@ var SmartComplySDK = (() => {
|
|
|
7775
7874
|
<div style="display:flex;flex-direction:column;align-items:center;gap:16px;padding:28px 20px;text-align:center;">
|
|
7776
7875
|
<div style="position:relative;width:52px;height:52px;">
|
|
7777
7876
|
<div style="position:absolute;inset:0;border-radius:50%;border:3px solid ${this.theme.border};border-top-color:${this.theme.primary};animation:sc-spin 0.8s linear infinite;"></div>
|
|
7778
|
-
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;"
|
|
7877
|
+
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔄</div>
|
|
7779
7878
|
</div>
|
|
7780
7879
|
<div style="color:${this.theme.text};font-size:14px;font-weight:600;">Retrying...</div>
|
|
7781
7880
|
<div style="color:${this.theme.textSecondary};font-size:12px;max-width:240px;line-height:1.5;">Attempt ${retryCount} of ${maxRetries}</div>
|
|
@@ -7816,7 +7915,7 @@ var SmartComplySDK = (() => {
|
|
|
7816
7915
|
wrap.setAttribute("role", "alert");
|
|
7817
7916
|
const icon = document.createElement("div");
|
|
7818
7917
|
icon.style.cssText = `width:56px;height:56px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:26px;`;
|
|
7819
|
-
icon.textContent = "
|
|
7918
|
+
icon.textContent = "🔍";
|
|
7820
7919
|
wrap.appendChild(icon);
|
|
7821
7920
|
const titleEl = document.createElement("div");
|
|
7822
7921
|
titleEl.style.cssText = `color:${this.theme.text};font-size:14px;font-weight:700;`;
|
|
@@ -7840,7 +7939,7 @@ var SmartComplySDK = (() => {
|
|
|
7840
7939
|
this.showErrorStep(userMessage);
|
|
7841
7940
|
}
|
|
7842
7941
|
}
|
|
7843
|
-
//
|
|
7942
|
+
// ── Liveness ────────────────────────────────────────────────────
|
|
7844
7943
|
renderLiveness(container) {
|
|
7845
7944
|
container.style.cssText += "display:flex;flex-direction:column;gap:14px;";
|
|
7846
7945
|
if (this._livenessFailures >= _SmartComplyFlow.MAX_RETRIES) {
|
|
@@ -7899,7 +7998,7 @@ var SmartComplySDK = (() => {
|
|
|
7899
7998
|
}
|
|
7900
7999
|
renderResult(_container) {
|
|
7901
8000
|
}
|
|
7902
|
-
//
|
|
8001
|
+
// ── Error ───────────────────────────────────────────────────────
|
|
7903
8002
|
showErrorStep(message) {
|
|
7904
8003
|
this.currentStep = "error";
|
|
7905
8004
|
if (!this.contentArea) return;
|
|
@@ -7916,7 +8015,7 @@ var SmartComplySDK = (() => {
|
|
|
7916
8015
|
const isDocQuality = /blurry|blur|quality|glare|dark|bright|lighting/i.test(message);
|
|
7917
8016
|
const isExpiredDoc = /document.*expired|expired.*document/i.test(message);
|
|
7918
8017
|
const isFaceMatch = /face.*match|selfie.*match|does not match/i.test(message);
|
|
7919
|
-
const errorIcon = isCameraErr ? "
|
|
8018
|
+
const errorIcon = isCameraErr ? "📷" : isNetworkErr ? "📡" : isAuthErr ? "⏱" : isDocQuality ? "🔍" : isExpiredDoc ? "📅" : isFaceMatch ? "🤳" : "✕";
|
|
7920
8019
|
const errorTitle = isCameraErr ? "Camera Access Required" : isNetworkErr ? "Connection Problem" : isAuthErr ? "Session Expired" : isDocQuality ? "Document Photo Unclear" : isExpiredDoc ? "Document Expired" : isFaceMatch ? "Face Match Failed" : "Verification Unsuccessful";
|
|
7921
8020
|
const userMessage = isCameraErr ? "Please allow camera access in your browser settings and try again." : isNetworkErr ? "Check your internet connection and try again." : isAuthErr ? "Your session has expired. Please start again." : isDocQuality ? _sanitizeUserMessage(message) || "Please retake your document photo in good lighting with no glare." : isExpiredDoc ? "The document you submitted has expired. Please use a valid, current ID." : isFaceMatch ? "Your selfie did not match the photo on your ID. Please ensure you are using your own valid document and face the camera directly." : _sanitizeUserMessage(message) || "We were unable to complete your verification. Please try again.";
|
|
7922
8021
|
const iconWrap = document.createElement("div");
|
|
@@ -7952,9 +8051,9 @@ var SmartComplySDK = (() => {
|
|
|
7952
8051
|
wrapper.appendChild(closeBtn);
|
|
7953
8052
|
this.contentArea.appendChild(wrapper);
|
|
7954
8053
|
}
|
|
7955
|
-
//
|
|
8054
|
+
// ─────────────────────────────────────────────────────────────────
|
|
7956
8055
|
// UI Helpers
|
|
7957
|
-
//
|
|
8056
|
+
// ─────────────────────────────────────────────────────────────────
|
|
7958
8057
|
createHeader() {
|
|
7959
8058
|
const header = document.createElement("div");
|
|
7960
8059
|
header.setAttribute("role", "banner");
|
|
@@ -8021,7 +8120,7 @@ var SmartComplySDK = (() => {
|
|
|
8021
8120
|
stepIndicator.appendChild(this.stepLabel);
|
|
8022
8121
|
header.appendChild(stepIndicator);
|
|
8023
8122
|
const closeBtn = document.createElement("button");
|
|
8024
|
-
closeBtn.innerHTML = "
|
|
8123
|
+
closeBtn.innerHTML = "✕";
|
|
8025
8124
|
closeBtn.setAttribute("aria-label", "Close identity verification");
|
|
8026
8125
|
closeBtn.style.cssText = `
|
|
8027
8126
|
width:32px;height:32px;border-radius:8px;flex-shrink:0;
|
|
@@ -8102,7 +8201,7 @@ var SmartComplySDK = (() => {
|
|
|
8102
8201
|
}
|
|
8103
8202
|
const arrow = document.createElement("span");
|
|
8104
8203
|
arrow.style.cssText = `color:${this.theme.textMuted};font-size:18px;flex-shrink:0;`;
|
|
8105
|
-
arrow.textContent = "
|
|
8204
|
+
arrow.textContent = "→";
|
|
8106
8205
|
card.appendChild(textWrap);
|
|
8107
8206
|
card.appendChild(arrow);
|
|
8108
8207
|
return card;
|
|
@@ -8174,7 +8273,7 @@ var SmartComplySDK = (() => {
|
|
|
8174
8273
|
if (this.currentStep === "loading" || this.currentStep === "welcome") {
|
|
8175
8274
|
this.stepLabel.textContent = "";
|
|
8176
8275
|
} else if (this.currentStep === "done" || this.currentStep === "result") {
|
|
8177
|
-
this.stepLabel.textContent = "Complete
|
|
8276
|
+
this.stepLabel.textContent = "Complete ✓";
|
|
8178
8277
|
} else if (stage2Steps.includes(this.currentStep)) {
|
|
8179
8278
|
this.stepLabel.textContent = "Stage 2 of 2: Face Check";
|
|
8180
8279
|
} else if (stage1Steps.includes(this.currentStep)) {
|