@koraidv/react 1.7.11 → 1.8.1
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/index.d.mts +55 -6
- package/dist/index.d.ts +55 -6
- package/dist/index.js +825 -379
- package/dist/index.mjs +828 -382
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -96,7 +96,8 @@ function useKoraIDV() {
|
|
|
96
96
|
currentChallenge: null,
|
|
97
97
|
completedChallenges: 0,
|
|
98
98
|
isLoading: false,
|
|
99
|
-
error: null
|
|
99
|
+
error: null,
|
|
100
|
+
lastChallengeError: null
|
|
100
101
|
});
|
|
101
102
|
const [selectedDocumentType, setSelectedDocumentType] = (0, import_react2.useState)(null);
|
|
102
103
|
const [documentFrontCaptured, setDocumentFrontCaptured] = (0, import_react2.useState)(false);
|
|
@@ -295,14 +296,20 @@ function useKoraIDV() {
|
|
|
295
296
|
...prev,
|
|
296
297
|
completedChallenges: nextIndex,
|
|
297
298
|
currentChallenge: nextChallenge,
|
|
298
|
-
isLoading: false
|
|
299
|
+
isLoading: false,
|
|
300
|
+
// Clear any prior retake message — the user just succeeded.
|
|
301
|
+
lastChallengeError: null
|
|
299
302
|
}));
|
|
300
303
|
if (!nextChallenge) {
|
|
301
304
|
setState((prev) => ({ ...prev, step: "processing" }));
|
|
302
305
|
}
|
|
303
306
|
return true;
|
|
304
307
|
}
|
|
305
|
-
setState((prev) => ({
|
|
308
|
+
setState((prev) => ({
|
|
309
|
+
...prev,
|
|
310
|
+
isLoading: false,
|
|
311
|
+
lastChallengeError: retakeMessageForChallenge(currentChallenge.type)
|
|
312
|
+
}));
|
|
306
313
|
return false;
|
|
307
314
|
} catch (error) {
|
|
308
315
|
setState((prev) => ({
|
|
@@ -353,7 +360,8 @@ function useKoraIDV() {
|
|
|
353
360
|
currentChallenge: null,
|
|
354
361
|
completedChallenges: 0,
|
|
355
362
|
isLoading: false,
|
|
356
|
-
error: null
|
|
363
|
+
error: null,
|
|
364
|
+
lastChallengeError: null
|
|
357
365
|
});
|
|
358
366
|
}, [sdk]);
|
|
359
367
|
const retry = (0, import_react2.useCallback)(() => {
|
|
@@ -380,9 +388,27 @@ function useKoraIDV() {
|
|
|
380
388
|
sdk
|
|
381
389
|
};
|
|
382
390
|
}
|
|
391
|
+
function retakeMessageForChallenge(type) {
|
|
392
|
+
switch (type) {
|
|
393
|
+
case "blink":
|
|
394
|
+
return "We didn't catch the blink \u2014 close both eyes briefly and try again.";
|
|
395
|
+
case "smile":
|
|
396
|
+
return "We didn't catch the smile \u2014 show your teeth and try again.";
|
|
397
|
+
case "turn_left":
|
|
398
|
+
return "Turn your head a bit further to the left and try again.";
|
|
399
|
+
case "turn_right":
|
|
400
|
+
return "Turn your head a bit further to the right and try again.";
|
|
401
|
+
case "nod_up":
|
|
402
|
+
return "Tilt your head a bit higher and try again.";
|
|
403
|
+
case "nod_down":
|
|
404
|
+
return "Tilt your head a bit lower and try again.";
|
|
405
|
+
default:
|
|
406
|
+
return "That attempt didn't pass \u2014 follow the prompt and try again.";
|
|
407
|
+
}
|
|
408
|
+
}
|
|
383
409
|
|
|
384
410
|
// src/components/VerificationFlow.tsx
|
|
385
|
-
var
|
|
411
|
+
var import_react13 = require("react");
|
|
386
412
|
var import_core4 = require("@koraidv/core");
|
|
387
413
|
|
|
388
414
|
// src/components/styles.ts
|
|
@@ -449,6 +475,36 @@ function injectKeyframes() {
|
|
|
449
475
|
from { opacity: 0; transform: translateY(8px); }
|
|
450
476
|
to { opacity: 1; transform: translateY(0); }
|
|
451
477
|
}
|
|
478
|
+
/* \u2500\u2500\u2500 VisualGuides motion (v1.8.0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
479
|
+
@keyframes kora-head-turn-right {
|
|
480
|
+
0%, 100% { transform: rotate(0deg); }
|
|
481
|
+
50% { transform: rotate(22deg); }
|
|
482
|
+
}
|
|
483
|
+
@keyframes kora-head-turn-left {
|
|
484
|
+
0%, 100% { transform: rotate(0deg); }
|
|
485
|
+
50% { transform: rotate(-22deg); }
|
|
486
|
+
}
|
|
487
|
+
@keyframes kora-head-tilt-up {
|
|
488
|
+
0%, 100% { transform: translateY(0); }
|
|
489
|
+
50% { transform: translateY(-6px) rotate(-6deg); }
|
|
490
|
+
}
|
|
491
|
+
@keyframes kora-head-tilt-down {
|
|
492
|
+
0%, 100% { transform: translateY(0); }
|
|
493
|
+
50% { transform: translateY(6px) rotate(6deg); }
|
|
494
|
+
}
|
|
495
|
+
@keyframes kora-smile {
|
|
496
|
+
0%, 100% { transform: scaleY(0.5); }
|
|
497
|
+
50% { transform: scaleY(1.2); }
|
|
498
|
+
}
|
|
499
|
+
@keyframes kora-blink {
|
|
500
|
+
0%, 80%, 100% { transform: scaleY(1); }
|
|
501
|
+
88% { transform: scaleY(0.05); }
|
|
502
|
+
}
|
|
503
|
+
@keyframes kora-nfc-wave {
|
|
504
|
+
0% { opacity: 0; transform: translateX(-4px); }
|
|
505
|
+
40% { opacity: 1; }
|
|
506
|
+
100% { opacity: 0; transform: translateX(6px); }
|
|
507
|
+
}
|
|
452
508
|
`;
|
|
453
509
|
document.head.appendChild(style);
|
|
454
510
|
}
|
|
@@ -1435,10 +1491,26 @@ function ScoreMetricRow({ label, score, icon, status, message }) {
|
|
|
1435
1491
|
}
|
|
1436
1492
|
);
|
|
1437
1493
|
}
|
|
1438
|
-
|
|
1494
|
+
var DEFAULT_AUTO_STEPS = [
|
|
1495
|
+
"Document analyzed",
|
|
1496
|
+
"Checking face match",
|
|
1497
|
+
"Finalizing results"
|
|
1498
|
+
];
|
|
1499
|
+
function ProcessingScreen({ steps, autoAdvance = true }) {
|
|
1439
1500
|
(0, import_react3.useEffect)(() => {
|
|
1440
1501
|
injectKeyframes();
|
|
1441
1502
|
}, []);
|
|
1503
|
+
const [autoIndex, setAutoIndex] = (0, import_react3.useState)(0);
|
|
1504
|
+
(0, import_react3.useEffect)(() => {
|
|
1505
|
+
if (steps || !autoAdvance) return;
|
|
1506
|
+
if (autoIndex >= DEFAULT_AUTO_STEPS.length - 1) return;
|
|
1507
|
+
const t = setTimeout(() => setAutoIndex((i) => i + 1), 1400);
|
|
1508
|
+
return () => clearTimeout(t);
|
|
1509
|
+
}, [autoIndex, steps, autoAdvance]);
|
|
1510
|
+
const renderedSteps = steps ? steps : DEFAULT_AUTO_STEPS.map((label, i) => ({
|
|
1511
|
+
label,
|
|
1512
|
+
status: i < autoIndex ? "done" : i === autoIndex ? "active" : "pending"
|
|
1513
|
+
}));
|
|
1442
1514
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.processingContainer, children: [
|
|
1443
1515
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.spinnerContainer, children: [
|
|
1444
1516
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -1489,7 +1561,7 @@ function ProcessingScreen({ steps }) {
|
|
|
1489
1561
|
}
|
|
1490
1562
|
)
|
|
1491
1563
|
] }),
|
|
1492
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.processingSteps, children:
|
|
1564
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.processingSteps, children: renderedSteps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.processingStep, children: [
|
|
1493
1565
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1494
1566
|
"div",
|
|
1495
1567
|
{
|
|
@@ -1514,6 +1586,7 @@ function ProcessingScreen({ steps }) {
|
|
|
1514
1586
|
] });
|
|
1515
1587
|
}
|
|
1516
1588
|
function computeScoreBreakdown(verification) {
|
|
1589
|
+
const source = verification.metadata?.source ?? "";
|
|
1517
1590
|
const livenessPercent = Math.round(
|
|
1518
1591
|
verification.scores?.liveness ?? verification.livenessVerification?.livenessScore ?? 0
|
|
1519
1592
|
);
|
|
@@ -1526,9 +1599,12 @@ function computeScoreBreakdown(verification) {
|
|
|
1526
1599
|
const selfiePercent = Math.round(
|
|
1527
1600
|
verification.scores?.faceMatch ?? verification.faceVerification?.matchScore ?? 0
|
|
1528
1601
|
);
|
|
1602
|
+
const isWeb = source === "web";
|
|
1603
|
+
const passFloor = isWeb ? 65 : 75;
|
|
1604
|
+
const borderlineFloor = isWeb ? 40 : 50;
|
|
1529
1605
|
function getStatus(score) {
|
|
1530
|
-
if (score >=
|
|
1531
|
-
if (score >=
|
|
1606
|
+
if (score >= passFloor) return "pass";
|
|
1607
|
+
if (score >= borderlineFloor) return "borderline";
|
|
1532
1608
|
return "fail";
|
|
1533
1609
|
}
|
|
1534
1610
|
function getMessage(status) {
|
|
@@ -1811,8 +1887,243 @@ function getIcon(type) {
|
|
|
1811
1887
|
}
|
|
1812
1888
|
|
|
1813
1889
|
// src/components/DocumentCaptureScreen.tsx
|
|
1890
|
+
var import_react7 = require("react");
|
|
1891
|
+
|
|
1892
|
+
// src/components/VisualGuides.tsx
|
|
1814
1893
|
var import_react5 = require("react");
|
|
1815
1894
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1895
|
+
function visualGuideForChallenge(challengeType) {
|
|
1896
|
+
switch (challengeType) {
|
|
1897
|
+
case "turn_left":
|
|
1898
|
+
return "livenessTurnLeft";
|
|
1899
|
+
case "turn_right":
|
|
1900
|
+
return "livenessTurnRight";
|
|
1901
|
+
case "nod_up":
|
|
1902
|
+
return "livenessLookUp";
|
|
1903
|
+
case "nod_down":
|
|
1904
|
+
return "livenessLookDown";
|
|
1905
|
+
case "smile":
|
|
1906
|
+
return "livenessSmile";
|
|
1907
|
+
case "blink":
|
|
1908
|
+
return "livenessBlink";
|
|
1909
|
+
default:
|
|
1910
|
+
return null;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
function VisualGuide({ kind, size = 96 }) {
|
|
1914
|
+
(0, import_react5.useEffect)(() => {
|
|
1915
|
+
injectKeyframes();
|
|
1916
|
+
}, []);
|
|
1917
|
+
const common = { width: size, height: size, viewBox: "0 0 100 100" };
|
|
1918
|
+
const fg = colors.teal;
|
|
1919
|
+
const dim = "rgba(255,255,255,0.3)";
|
|
1920
|
+
switch (kind) {
|
|
1921
|
+
case "docFront":
|
|
1922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DocFront, { ...common, fg, dim });
|
|
1923
|
+
case "docBack":
|
|
1924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DocBack, { ...common, fg, dim });
|
|
1925
|
+
case "selfie":
|
|
1926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Selfie, { ...common, fg, dim });
|
|
1927
|
+
case "nfcScan":
|
|
1928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NfcScan, { ...common, fg, dim });
|
|
1929
|
+
case "livenessTurnLeft":
|
|
1930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HeadTurn, { ...common, fg, dim, right: false });
|
|
1931
|
+
case "livenessTurnRight":
|
|
1932
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HeadTurn, { ...common, fg, dim, right: true });
|
|
1933
|
+
case "livenessLookUp":
|
|
1934
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HeadTilt, { ...common, fg, dim, up: true });
|
|
1935
|
+
case "livenessLookDown":
|
|
1936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HeadTilt, { ...common, fg, dim, up: false });
|
|
1937
|
+
case "livenessSmile":
|
|
1938
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Smile, { ...common, fg, dim });
|
|
1939
|
+
case "livenessBlink":
|
|
1940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Blink, { ...common, fg, dim });
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
function DocFront({ width, height, viewBox, fg, dim }) {
|
|
1944
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
1945
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "8", y: "26", width: "84", height: "48", rx: "5", stroke: fg, strokeWidth: "2.5" }),
|
|
1946
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "14", y: "34", width: "22", height: "28", rx: "2", fill: dim }),
|
|
1947
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "42", y: "36", width: "44", height: "3", rx: "1.5", fill: fg }),
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "42", y: "44", width: "36", height: "2.5", rx: "1.25", fill: dim }),
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "42", y: "50", width: "40", height: "2.5", rx: "1.25", fill: dim }),
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "42", y: "56", width: "30", height: "2.5", rx: "1.25", fill: dim })
|
|
1951
|
+
] });
|
|
1952
|
+
}
|
|
1953
|
+
function DocBack({ width, height, viewBox, fg, dim }) {
|
|
1954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
1955
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "8", y: "26", width: "84", height: "48", rx: "5", stroke: fg, strokeWidth: "2.5" }),
|
|
1956
|
+
[16, 19, 22, 26, 28, 32, 35, 39, 42, 46, 49, 53, 56, 60].map((x, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1957
|
+
"rect",
|
|
1958
|
+
{
|
|
1959
|
+
x,
|
|
1960
|
+
y: "34",
|
|
1961
|
+
width: i % 3 === 0 ? 2 : 1.2,
|
|
1962
|
+
height: "20",
|
|
1963
|
+
fill: fg
|
|
1964
|
+
},
|
|
1965
|
+
i
|
|
1966
|
+
)),
|
|
1967
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "14", y1: "64", x2: "58", y2: "64", stroke: dim, strokeWidth: "1.5" }),
|
|
1968
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "66", y: "34", width: "20", height: "20", rx: "1", fill: dim })
|
|
1969
|
+
] });
|
|
1970
|
+
}
|
|
1971
|
+
function Selfie({ width, height, viewBox, fg, dim }) {
|
|
1972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
1973
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ellipse", { cx: "50", cy: "42", rx: "22", ry: "28", stroke: fg, strokeWidth: "2.5" }),
|
|
1974
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "42", cy: "38", r: "2.5", fill: fg }),
|
|
1975
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "58", cy: "38", r: "2.5", fill: fg }),
|
|
1976
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 40 50 Q 50 56 60 50", stroke: fg, strokeWidth: "2", strokeLinecap: "round", fill: "none" }),
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 18 92 Q 18 76 36 70 L 64 70 Q 82 76 82 92", stroke: dim, strokeWidth: "2", fill: "none" })
|
|
1978
|
+
] });
|
|
1979
|
+
}
|
|
1980
|
+
function NfcScan({ width, height, viewBox, fg, dim }) {
|
|
1981
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
1982
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "14", y: "40", width: "40", height: "50", rx: "3", stroke: dim, strokeWidth: "2" }),
|
|
1983
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "34", cy: "60", r: "6", stroke: dim, strokeWidth: "1.5" }),
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "62", y: "22", width: "26", height: "52", rx: "4", stroke: fg, strokeWidth: "2.5" }),
|
|
1985
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "66", y: "26", width: "18", height: "38", rx: "1.5", fill: dim, opacity: "0.5" }),
|
|
1986
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 58 48 Q 52 48 50 56", stroke: fg, strokeWidth: "2", fill: "none", style: { animation: "kora-nfc-wave 1.6s ease-out infinite" } }),
|
|
1987
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 58 44 Q 50 44 46 56", stroke: fg, strokeWidth: "2", fill: "none", opacity: "0.7", style: { animation: "kora-nfc-wave 1.6s ease-out infinite 0.3s" } })
|
|
1988
|
+
] });
|
|
1989
|
+
}
|
|
1990
|
+
function HeadTurn({ width, height, viewBox, fg, dim, right }) {
|
|
1991
|
+
const arrowPath = right ? "M 30 12 L 70 12 L 64 6 M 70 12 L 64 18" : "M 70 12 L 30 12 L 36 6 M 30 12 L 36 18";
|
|
1992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
1993
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: arrowPath, stroke: fg, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
|
|
1994
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1995
|
+
"g",
|
|
1996
|
+
{
|
|
1997
|
+
style: {
|
|
1998
|
+
transformOrigin: "50px 56px",
|
|
1999
|
+
animation: right ? "kora-head-turn-right 2s ease-in-out infinite" : "kora-head-turn-left 2s ease-in-out infinite"
|
|
2000
|
+
},
|
|
2001
|
+
children: [
|
|
2002
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ellipse", { cx: "50", cy: "55", rx: "20", ry: "26", stroke: fg, strokeWidth: "2.5" }),
|
|
2003
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "42", cy: "50", r: "2", fill: fg }),
|
|
2004
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "58", cy: "50", r: "2", fill: fg }),
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 50 54 L 50 62", stroke: dim, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
2006
|
+
]
|
|
2007
|
+
}
|
|
2008
|
+
)
|
|
2009
|
+
] });
|
|
2010
|
+
}
|
|
2011
|
+
function HeadTilt({ width, height, viewBox, fg, dim, up }) {
|
|
2012
|
+
const arrowPath = up ? "M 50 92 L 50 14 M 44 22 L 50 14 L 56 22" : "M 50 14 L 50 92 M 44 84 L 50 92 L 56 84";
|
|
2013
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: arrowPath, stroke: fg, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", opacity: "0.4", fill: "none" }),
|
|
2015
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2016
|
+
"g",
|
|
2017
|
+
{
|
|
2018
|
+
style: {
|
|
2019
|
+
transformOrigin: "50px 56px",
|
|
2020
|
+
animation: up ? "kora-head-tilt-up 2s ease-in-out infinite" : "kora-head-tilt-down 2s ease-in-out infinite"
|
|
2021
|
+
},
|
|
2022
|
+
children: [
|
|
2023
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ellipse", { cx: "50", cy: "55", rx: "20", ry: "26", stroke: fg, strokeWidth: "2.5" }),
|
|
2024
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "42", cy: "50", r: "2", fill: fg }),
|
|
2025
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "58", cy: "50", r: "2", fill: fg }),
|
|
2026
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 50 54 L 50 62", stroke: dim, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
2027
|
+
]
|
|
2028
|
+
}
|
|
2029
|
+
)
|
|
2030
|
+
] });
|
|
2031
|
+
}
|
|
2032
|
+
function Smile({ width, height, viewBox, fg, dim }) {
|
|
2033
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
2034
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ellipse", { cx: "50", cy: "50", rx: "24", ry: "30", stroke: fg, strokeWidth: "2.5" }),
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "40", cy: "44", r: "2.5", fill: fg }),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "60", cy: "44", r: "2.5", fill: fg }),
|
|
2037
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2038
|
+
"path",
|
|
2039
|
+
{
|
|
2040
|
+
d: "M 38 60 Q 50 68 62 60",
|
|
2041
|
+
stroke: fg,
|
|
2042
|
+
strokeWidth: "2.5",
|
|
2043
|
+
strokeLinecap: "round",
|
|
2044
|
+
fill: "none",
|
|
2045
|
+
style: { animation: "kora-smile 2s ease-in-out infinite", transformOrigin: "50px 60px" }
|
|
2046
|
+
}
|
|
2047
|
+
),
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "40", y1: "60", x2: "60", y2: "60", stroke: dim, strokeWidth: "1.5", opacity: "0.3" })
|
|
2049
|
+
] });
|
|
2050
|
+
}
|
|
2051
|
+
function Blink({ width, height, viewBox, fg, dim }) {
|
|
2052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width, height, viewBox, fill: "none", children: [
|
|
2053
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ellipse", { cx: "50", cy: "50", rx: "24", ry: "30", stroke: fg, strokeWidth: "2.5" }),
|
|
2054
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("g", { style: { animation: "kora-blink 1.6s ease-in-out infinite" }, children: [
|
|
2055
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "40", cy: "44", r: "3", fill: fg }),
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "60", cy: "44", r: "3", fill: fg })
|
|
2057
|
+
] }),
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M 42 60 Q 50 64 58 60", stroke: dim, strokeWidth: "2", strokeLinecap: "round", fill: "none" })
|
|
2059
|
+
] });
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
// src/hooks/useDocumentDetection.ts
|
|
2063
|
+
var import_react6 = require("react");
|
|
2064
|
+
var FRAME_INTERVAL_MS = 300;
|
|
2065
|
+
function useDocumentDetection(videoRef, side) {
|
|
2066
|
+
const [signals, setSignals] = (0, import_react6.useState)({
|
|
2067
|
+
documentDetected: false,
|
|
2068
|
+
detectorActive: false
|
|
2069
|
+
});
|
|
2070
|
+
const detectorRef = (0, import_react6.useRef)(null);
|
|
2071
|
+
const intervalRef = (0, import_react6.useRef)(null);
|
|
2072
|
+
(0, import_react6.useEffect)(() => {
|
|
2073
|
+
let cancelled = false;
|
|
2074
|
+
async function setup() {
|
|
2075
|
+
const win = typeof window !== "undefined" ? window : null;
|
|
2076
|
+
if (!win) return;
|
|
2077
|
+
let DetectorCtor = null;
|
|
2078
|
+
if (side === "front" && "FaceDetector" in win) {
|
|
2079
|
+
DetectorCtor = win["FaceDetector"];
|
|
2080
|
+
} else if (side === "back" && "BarcodeDetector" in win) {
|
|
2081
|
+
DetectorCtor = win["BarcodeDetector"];
|
|
2082
|
+
}
|
|
2083
|
+
if (!DetectorCtor) {
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
try {
|
|
2087
|
+
const detector = new DetectorCtor(
|
|
2088
|
+
side === "front" ? { fastMode: true, maxDetectedFaces: 1 } : { formats: ["pdf417", "qr_code", "data_matrix", "code_128"] }
|
|
2089
|
+
);
|
|
2090
|
+
if (cancelled) return;
|
|
2091
|
+
detectorRef.current = detector;
|
|
2092
|
+
setSignals((prev) => ({ ...prev, detectorActive: true }));
|
|
2093
|
+
} catch {
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
intervalRef.current = setInterval(async () => {
|
|
2097
|
+
const detector = detectorRef.current;
|
|
2098
|
+
const video = videoRef.current;
|
|
2099
|
+
if (!detector || !video || video.readyState < 2) return;
|
|
2100
|
+
try {
|
|
2101
|
+
const results = await detector.detect(video);
|
|
2102
|
+
if (cancelled) return;
|
|
2103
|
+
setSignals((prev) => {
|
|
2104
|
+
const next = results.length > 0;
|
|
2105
|
+
if (prev.documentDetected === next) return prev;
|
|
2106
|
+
return { ...prev, documentDetected: next };
|
|
2107
|
+
});
|
|
2108
|
+
} catch {
|
|
2109
|
+
}
|
|
2110
|
+
}, FRAME_INTERVAL_MS);
|
|
2111
|
+
}
|
|
2112
|
+
setup();
|
|
2113
|
+
return () => {
|
|
2114
|
+
cancelled = true;
|
|
2115
|
+
if (intervalRef.current) {
|
|
2116
|
+
clearInterval(intervalRef.current);
|
|
2117
|
+
intervalRef.current = null;
|
|
2118
|
+
}
|
|
2119
|
+
detectorRef.current = null;
|
|
2120
|
+
};
|
|
2121
|
+
}, [videoRef, side]);
|
|
2122
|
+
return signals;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
// src/components/DocumentCaptureScreen.tsx
|
|
2126
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1816
2127
|
var qualityIssueMessages = {
|
|
1817
2128
|
face_blurred: "Photo on document is blurry. Retake in better lighting.",
|
|
1818
2129
|
low_resolution: "Image quality too low. Move closer to document.",
|
|
@@ -1829,23 +2140,25 @@ function DocumentCaptureScreen({
|
|
|
1829
2140
|
requiresBack = true,
|
|
1830
2141
|
onQualityCheck,
|
|
1831
2142
|
onCapture,
|
|
1832
|
-
onCancel
|
|
2143
|
+
onCancel,
|
|
2144
|
+
showVisualGuides = true
|
|
1833
2145
|
}) {
|
|
1834
|
-
const videoRef = (0,
|
|
1835
|
-
const canvasRef = (0,
|
|
1836
|
-
const guideRef = (0,
|
|
1837
|
-
const [stream, setStream] = (0,
|
|
1838
|
-
const
|
|
1839
|
-
const [
|
|
1840
|
-
const [
|
|
1841
|
-
const [
|
|
1842
|
-
const [
|
|
1843
|
-
const [
|
|
1844
|
-
const [
|
|
1845
|
-
(0,
|
|
2146
|
+
const videoRef = (0, import_react7.useRef)(null);
|
|
2147
|
+
const canvasRef = (0, import_react7.useRef)(null);
|
|
2148
|
+
const guideRef = (0, import_react7.useRef)(null);
|
|
2149
|
+
const [stream, setStream] = (0, import_react7.useState)(null);
|
|
2150
|
+
const documentSignals = useDocumentDetection(videoRef, side);
|
|
2151
|
+
const [isCapturing, setIsCapturing] = (0, import_react7.useState)(false);
|
|
2152
|
+
const [error, setError] = (0, import_react7.useState)(null);
|
|
2153
|
+
const [capturedImage, setCapturedImage] = (0, import_react7.useState)(null);
|
|
2154
|
+
const [capturedBlob, setCapturedBlob] = (0, import_react7.useState)(null);
|
|
2155
|
+
const [qualityResult, setQualityResult] = (0, import_react7.useState)(null);
|
|
2156
|
+
const [isCheckingQuality, setIsCheckingQuality] = (0, import_react7.useState)(false);
|
|
2157
|
+
const [retakeCount, setRetakeCount] = (0, import_react7.useState)(0);
|
|
2158
|
+
(0, import_react7.useEffect)(() => {
|
|
1846
2159
|
injectKeyframes();
|
|
1847
2160
|
}, []);
|
|
1848
|
-
(0,
|
|
2161
|
+
(0, import_react7.useEffect)(() => {
|
|
1849
2162
|
let mounted = true;
|
|
1850
2163
|
async function startCamera() {
|
|
1851
2164
|
try {
|
|
@@ -1867,12 +2180,12 @@ function DocumentCaptureScreen({
|
|
|
1867
2180
|
mounted = false;
|
|
1868
2181
|
};
|
|
1869
2182
|
}, [capturedImage]);
|
|
1870
|
-
(0,
|
|
2183
|
+
(0, import_react7.useEffect)(() => {
|
|
1871
2184
|
return () => {
|
|
1872
2185
|
stream?.getTracks().forEach((t) => t.stop());
|
|
1873
2186
|
};
|
|
1874
2187
|
}, [stream]);
|
|
1875
|
-
const handleCapture = (0,
|
|
2188
|
+
const handleCapture = (0, import_react7.useCallback)(() => {
|
|
1876
2189
|
if (!videoRef.current || !canvasRef.current || isCapturing) return;
|
|
1877
2190
|
setIsCapturing(true);
|
|
1878
2191
|
const video = videoRef.current;
|
|
@@ -1960,24 +2273,24 @@ function DocumentCaptureScreen({
|
|
|
1960
2273
|
}
|
|
1961
2274
|
};
|
|
1962
2275
|
if (error) {
|
|
1963
|
-
return /* @__PURE__ */ (0,
|
|
1964
|
-
/* @__PURE__ */ (0,
|
|
1965
|
-
/* @__PURE__ */ (0,
|
|
2276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.errorContainer, children: [
|
|
2277
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.errorText, children: error }),
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: styles.primaryButton, onClick: onCancel, children: "Go Back" })
|
|
1966
2279
|
] }) });
|
|
1967
2280
|
}
|
|
1968
2281
|
if (capturedImage) {
|
|
1969
2282
|
const qualityPassed = qualityResult && qualityResult.qualityScore >= 60;
|
|
1970
2283
|
const qualityFailed = qualityResult && qualityResult.qualityScore < 60;
|
|
1971
2284
|
const canContinueAnyway = qualityFailed && retakeCount >= 2;
|
|
1972
|
-
return /* @__PURE__ */ (0,
|
|
1973
|
-
/* @__PURE__ */ (0,
|
|
1974
|
-
/* @__PURE__ */ (0,
|
|
1975
|
-
/* @__PURE__ */ (0,
|
|
1976
|
-
/* @__PURE__ */ (0,
|
|
1977
|
-
/* @__PURE__ */ (0,
|
|
2285
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.darkContainer, children: [
|
|
2286
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StepProgressBar, { total: 5, current: 3, isDark: true }),
|
|
2287
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.darkScreenHeader, children: [
|
|
2288
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: 40 } }),
|
|
2289
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: styles.darkScreenTitle, children: "Review your photo" }),
|
|
2290
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
1978
2291
|
] }),
|
|
1979
|
-
/* @__PURE__ */ (0,
|
|
1980
|
-
/* @__PURE__ */ (0,
|
|
2292
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.reviewCard, children: [
|
|
2293
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1981
2294
|
"img",
|
|
1982
2295
|
{
|
|
1983
2296
|
src: capturedImage,
|
|
@@ -1985,42 +2298,42 @@ function DocumentCaptureScreen({
|
|
|
1985
2298
|
style: { width: "100%", maxWidth: "300px", borderRadius: "16px", display: "block", margin: "0 auto" }
|
|
1986
2299
|
}
|
|
1987
2300
|
),
|
|
1988
|
-
isCheckingQuality && /* @__PURE__ */ (0,
|
|
1989
|
-
qualityPassed && /* @__PURE__ */ (0,
|
|
1990
|
-
/* @__PURE__ */ (0,
|
|
2301
|
+
isCheckingQuality && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...styles.reviewBadge, backgroundColor: "rgba(255,255,255,0.1)" }, children: "Checking quality..." }) }),
|
|
2302
|
+
qualityPassed && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: styles.reviewBadge, children: [
|
|
1991
2304
|
"\u2713 Quality score: ",
|
|
1992
2305
|
Math.round(qualityResult.qualityScore),
|
|
1993
2306
|
"%"
|
|
1994
2307
|
] }) }),
|
|
1995
|
-
/* @__PURE__ */ (0,
|
|
1996
|
-
/* @__PURE__ */ (0,
|
|
1997
|
-
/* @__PURE__ */ (0,
|
|
1998
|
-
/* @__PURE__ */ (0,
|
|
2308
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.qualityChecks, children: [
|
|
2309
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QualityCheck, { label: "Sharp" }),
|
|
2310
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QualityCheck, { label: "Well-lit" }),
|
|
2311
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QualityCheck, { label: "Readable" })
|
|
1999
2312
|
] })
|
|
2000
2313
|
] }),
|
|
2001
|
-
qualityFailed && /* @__PURE__ */ (0,
|
|
2002
|
-
/* @__PURE__ */ (0,
|
|
2314
|
+
qualityFailed && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2315
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { ...styles.reviewBadge, backgroundColor: "rgba(239,68,68,0.15)", color: "#ef4444" }, children: [
|
|
2003
2316
|
"\u26A0 Quality score: ",
|
|
2004
2317
|
Math.round(qualityResult.qualityScore),
|
|
2005
2318
|
"%"
|
|
2006
2319
|
] }) }),
|
|
2007
|
-
/* @__PURE__ */ (0,
|
|
2320
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { padding: "12px 0" }, children: qualityResult.qualityIssues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: { color: "rgba(255,255,255,0.7)", fontSize: "13px", margin: "4px 0", textAlign: "center" }, children: qualityIssueMessages[issue] || issue }, i)) })
|
|
2008
2321
|
] }),
|
|
2009
|
-
!qualityResult && !isCheckingQuality && /* @__PURE__ */ (0,
|
|
2010
|
-
/* @__PURE__ */ (0,
|
|
2011
|
-
/* @__PURE__ */ (0,
|
|
2012
|
-
/* @__PURE__ */ (0,
|
|
2013
|
-
/* @__PURE__ */ (0,
|
|
2014
|
-
/* @__PURE__ */ (0,
|
|
2322
|
+
!qualityResult && !isCheckingQuality && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2323
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.reviewBadge, children: "\u2713 Good quality" }) }),
|
|
2324
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.qualityChecks, children: [
|
|
2325
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QualityCheck, { label: "Sharp" }),
|
|
2326
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QualityCheck, { label: "Well-lit" }),
|
|
2327
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QualityCheck, { label: "No glare" })
|
|
2015
2328
|
] })
|
|
2016
2329
|
] })
|
|
2017
2330
|
] }) }),
|
|
2018
|
-
/* @__PURE__ */ (0,
|
|
2019
|
-
/* @__PURE__ */ (0,
|
|
2020
|
-
canContinueAnyway && /* @__PURE__ */ (0,
|
|
2021
|
-
] }) : /* @__PURE__ */ (0,
|
|
2022
|
-
/* @__PURE__ */ (0,
|
|
2023
|
-
/* @__PURE__ */ (0,
|
|
2331
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.reviewButtonsRow, children: qualityFailed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2332
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: { ...styles.darkOutlineButton, flex: 1 }, onClick: handleRetake, children: "Retake" }),
|
|
2333
|
+
canContinueAnyway && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: { ...styles.primaryButton, flex: 1 }, onClick: handleContinueAnyway, children: "Continue anyway" })
|
|
2334
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2335
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: { ...styles.darkOutlineButton, flex: 1 }, onClick: handleRetake, children: "Retake" }),
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2024
2337
|
"button",
|
|
2025
2338
|
{
|
|
2026
2339
|
style: { ...styles.primaryButton, flex: 1, opacity: isCheckingQuality ? 0.5 : 1 },
|
|
@@ -2032,29 +2345,54 @@ function DocumentCaptureScreen({
|
|
|
2032
2345
|
] }) })
|
|
2033
2346
|
] });
|
|
2034
2347
|
}
|
|
2035
|
-
return /* @__PURE__ */ (0,
|
|
2036
|
-
/* @__PURE__ */ (0,
|
|
2037
|
-
/* @__PURE__ */ (0,
|
|
2038
|
-
/* @__PURE__ */ (0,
|
|
2039
|
-
/* @__PURE__ */ (0,
|
|
2040
|
-
/* @__PURE__ */ (0,
|
|
2041
|
-
documentType && /* @__PURE__ */ (0,
|
|
2348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.captureContainer, children: [
|
|
2349
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StepProgressBar, { total: 5, current: 3, isDark: true }),
|
|
2350
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.darkScreenHeader, children: [
|
|
2351
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: 40 } }),
|
|
2352
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { flex: 1, textAlign: "center" }, children: [
|
|
2353
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: { ...styles.darkScreenTitle, margin: 0 }, children: side === "front" ? "Front of ID" : "Back of ID" }),
|
|
2354
|
+
documentType && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.darkScreenSubtitle, children: documentType })
|
|
2042
2355
|
] }),
|
|
2043
|
-
/* @__PURE__ */ (0,
|
|
2356
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2044
2357
|
] }),
|
|
2045
|
-
/* @__PURE__ */ (0,
|
|
2046
|
-
|
|
2047
|
-
/* @__PURE__ */ (0,
|
|
2048
|
-
|
|
2049
|
-
/* @__PURE__ */ (0,
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2358
|
+
showVisualGuides && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "6px 0 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(VisualGuide, { kind: side === "front" ? "docFront" : "docBack", size: 56 }) }),
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.cameraContainer, children: [
|
|
2360
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, style: styles.cameraVideo }),
|
|
2361
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.documentOverlay, children: [
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: guideRef, style: styles.documentFrame, children: [
|
|
2363
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...styles.corner, top: 0, left: 0 } }),
|
|
2364
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...styles.corner, top: 0, right: 0, transform: "rotate(90deg)" } }),
|
|
2365
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...styles.corner, bottom: 0, right: 0, transform: "rotate(180deg)" } }),
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...styles.corner, bottom: 0, left: 0, transform: "rotate(270deg)" } }),
|
|
2367
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.scanLine })
|
|
2368
|
+
] }),
|
|
2369
|
+
documentSignals.detectorActive && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2370
|
+
"div",
|
|
2371
|
+
{
|
|
2372
|
+
style: {
|
|
2373
|
+
position: "absolute",
|
|
2374
|
+
bottom: "24px",
|
|
2375
|
+
left: "50%",
|
|
2376
|
+
transform: "translateX(-50%)",
|
|
2377
|
+
padding: "6px 14px",
|
|
2378
|
+
borderRadius: "999px",
|
|
2379
|
+
fontSize: "12px",
|
|
2380
|
+
fontWeight: 600,
|
|
2381
|
+
color: documentSignals.documentDetected ? colors.success : "rgba(255,255,255,0.55)",
|
|
2382
|
+
backgroundColor: documentSignals.documentDetected ? "rgba(16,185,129,0.15)" : "rgba(0,0,0,0.35)",
|
|
2383
|
+
border: documentSignals.documentDetected ? "1px solid rgba(16,185,129,0.4)" : "1px solid rgba(255,255,255,0.12)",
|
|
2384
|
+
transition: "all 200ms",
|
|
2385
|
+
pointerEvents: "none",
|
|
2386
|
+
whiteSpace: "nowrap"
|
|
2387
|
+
},
|
|
2388
|
+
children: documentSignals.documentDetected ? "\u2713 Document detected \u2014 fill the frame" : "Position your ID inside the guide"
|
|
2389
|
+
}
|
|
2390
|
+
)
|
|
2391
|
+
] }),
|
|
2392
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("canvas", { ref: canvasRef, style: { display: "none" } })
|
|
2055
2393
|
] }),
|
|
2056
|
-
/* @__PURE__ */ (0,
|
|
2057
|
-
/* @__PURE__ */ (0,
|
|
2394
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.stepPillsRow, children: [
|
|
2395
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2058
2396
|
"span",
|
|
2059
2397
|
{
|
|
2060
2398
|
style: {
|
|
@@ -2065,7 +2403,7 @@ function DocumentCaptureScreen({
|
|
|
2065
2403
|
children: "Front"
|
|
2066
2404
|
}
|
|
2067
2405
|
),
|
|
2068
|
-
requiresBack && /* @__PURE__ */ (0,
|
|
2406
|
+
requiresBack && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2069
2407
|
"span",
|
|
2070
2408
|
{
|
|
2071
2409
|
style: {
|
|
@@ -2077,7 +2415,7 @@ function DocumentCaptureScreen({
|
|
|
2077
2415
|
}
|
|
2078
2416
|
)
|
|
2079
2417
|
] }),
|
|
2080
|
-
/* @__PURE__ */ (0,
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { textAlign: "center", padding: "8px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2081
2419
|
"span",
|
|
2082
2420
|
{
|
|
2083
2421
|
style: {
|
|
@@ -2086,44 +2424,44 @@ function DocumentCaptureScreen({
|
|
|
2086
2424
|
color: colors.teal
|
|
2087
2425
|
},
|
|
2088
2426
|
children: [
|
|
2089
|
-
/* @__PURE__ */ (0,
|
|
2427
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...styles.pulsingDot, backgroundColor: colors.teal } }),
|
|
2090
2428
|
"Scanning document..."
|
|
2091
2429
|
]
|
|
2092
2430
|
}
|
|
2093
2431
|
) }),
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2432
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.captureFooter, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2095
2433
|
"button",
|
|
2096
2434
|
{
|
|
2097
2435
|
style: { ...styles.captureButton, opacity: isCapturing ? 0.5 : 1 },
|
|
2098
2436
|
onClick: handleCapture,
|
|
2099
2437
|
disabled: isCapturing,
|
|
2100
|
-
children: /* @__PURE__ */ (0,
|
|
2438
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.captureButtonInner })
|
|
2101
2439
|
}
|
|
2102
2440
|
) })
|
|
2103
2441
|
] });
|
|
2104
2442
|
}
|
|
2105
2443
|
function QualityCheck({ label }) {
|
|
2106
|
-
return /* @__PURE__ */ (0,
|
|
2107
|
-
/* @__PURE__ */ (0,
|
|
2108
|
-
/* @__PURE__ */ (0,
|
|
2444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.qualityCheck, children: [
|
|
2445
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.qualityCheckIcon, children: "\u2713" }),
|
|
2446
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.qualityCheckLabel, children: label })
|
|
2109
2447
|
] });
|
|
2110
2448
|
}
|
|
2111
2449
|
|
|
2112
2450
|
// src/components/FlipDocumentScreen.tsx
|
|
2113
|
-
var
|
|
2114
|
-
var
|
|
2451
|
+
var import_react8 = require("react");
|
|
2452
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2115
2453
|
function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
2116
|
-
(0,
|
|
2454
|
+
(0, import_react8.useEffect)(() => {
|
|
2117
2455
|
injectKeyframes();
|
|
2118
2456
|
}, []);
|
|
2119
|
-
return /* @__PURE__ */ (0,
|
|
2120
|
-
/* @__PURE__ */ (0,
|
|
2121
|
-
/* @__PURE__ */ (0,
|
|
2122
|
-
/* @__PURE__ */ (0,
|
|
2123
|
-
/* @__PURE__ */ (0,
|
|
2124
|
-
/* @__PURE__ */ (0,
|
|
2457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.darkContainer, children: [
|
|
2458
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StepProgressBar, { total: 5, current: 3, isDark: true }),
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.darkScreenHeader, children: [
|
|
2460
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { width: 40 } }),
|
|
2461
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: styles.darkScreenTitle, children: "Flip your document" }),
|
|
2462
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2125
2463
|
] }),
|
|
2126
|
-
/* @__PURE__ */ (0,
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: {
|
|
2127
2465
|
flex: 1,
|
|
2128
2466
|
display: "flex",
|
|
2129
2467
|
flexDirection: "column",
|
|
@@ -2132,7 +2470,7 @@ function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
|
2132
2470
|
padding: "24px",
|
|
2133
2471
|
gap: "32px"
|
|
2134
2472
|
}, children: [
|
|
2135
|
-
/* @__PURE__ */ (0,
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
|
|
2136
2474
|
width: "120px",
|
|
2137
2475
|
height: "120px",
|
|
2138
2476
|
borderRadius: "50%",
|
|
@@ -2140,18 +2478,18 @@ function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
|
2140
2478
|
display: "flex",
|
|
2141
2479
|
alignItems: "center",
|
|
2142
2480
|
justifyContent: "center"
|
|
2143
|
-
}, children: /* @__PURE__ */ (0,
|
|
2144
|
-
/* @__PURE__ */ (0,
|
|
2145
|
-
/* @__PURE__ */ (0,
|
|
2481
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "56", height: "56", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
2482
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M9 3L5 6.99H8V14H10V6.99H13L9 3Z", fill: colors.teal }),
|
|
2483
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M16 17.01V10H14V17.01H11L15 21L19 17.01H16Z", fill: colors.teal })
|
|
2146
2484
|
] }) }),
|
|
2147
|
-
/* @__PURE__ */ (0,
|
|
2148
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { textAlign: "center" }, children: [
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: {
|
|
2149
2487
|
fontSize: "22px",
|
|
2150
2488
|
fontWeight: 700,
|
|
2151
2489
|
color: colors.white,
|
|
2152
2490
|
margin: "0 0 12px 0"
|
|
2153
2491
|
}, children: "Now capture the back" }),
|
|
2154
|
-
/* @__PURE__ */ (0,
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: {
|
|
2155
2493
|
fontSize: "15px",
|
|
2156
2494
|
color: "rgba(255,255,255,0.6)",
|
|
2157
2495
|
margin: 0,
|
|
@@ -2159,38 +2497,38 @@ function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
|
2159
2497
|
maxWidth: "280px"
|
|
2160
2498
|
}, children: "Turn your document over to the back side, then tap continue to take a photo." })
|
|
2161
2499
|
] }),
|
|
2162
|
-
/* @__PURE__ */ (0,
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.stepPillsRow, children: [
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: {
|
|
2164
2502
|
...styles.stepPill,
|
|
2165
2503
|
backgroundColor: "rgba(16,185,129,0.15)",
|
|
2166
2504
|
color: colors.success
|
|
2167
2505
|
}, children: "\u2713 Front" }),
|
|
2168
|
-
/* @__PURE__ */ (0,
|
|
2506
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: {
|
|
2169
2507
|
...styles.stepPill,
|
|
2170
2508
|
backgroundColor: colors.teal,
|
|
2171
2509
|
color: colors.white
|
|
2172
2510
|
}, children: "Back" })
|
|
2173
2511
|
] })
|
|
2174
2512
|
] }),
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2513
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { padding: "24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { style: styles.primaryButton, onClick: onContinue, children: "Continue" }) })
|
|
2176
2514
|
] });
|
|
2177
2515
|
}
|
|
2178
2516
|
|
|
2179
2517
|
// src/components/SelfieCaptureScreen.tsx
|
|
2180
|
-
var
|
|
2181
|
-
var
|
|
2182
|
-
function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
2183
|
-
const videoRef = (0,
|
|
2184
|
-
const canvasRef = (0,
|
|
2185
|
-
const [stream, setStream] = (0,
|
|
2186
|
-
const [isCapturing, setIsCapturing] = (0,
|
|
2187
|
-
const [error, setError] = (0,
|
|
2188
|
-
const [capturedImage, setCapturedImage] = (0,
|
|
2189
|
-
const [capturedBlob, setCapturedBlob] = (0,
|
|
2190
|
-
(0,
|
|
2518
|
+
var import_react9 = require("react");
|
|
2519
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2520
|
+
function SelfieCaptureScreen({ onCapture, onCancel, showVisualGuides = true }) {
|
|
2521
|
+
const videoRef = (0, import_react9.useRef)(null);
|
|
2522
|
+
const canvasRef = (0, import_react9.useRef)(null);
|
|
2523
|
+
const [stream, setStream] = (0, import_react9.useState)(null);
|
|
2524
|
+
const [isCapturing, setIsCapturing] = (0, import_react9.useState)(false);
|
|
2525
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
2526
|
+
const [capturedImage, setCapturedImage] = (0, import_react9.useState)(null);
|
|
2527
|
+
const [capturedBlob, setCapturedBlob] = (0, import_react9.useState)(null);
|
|
2528
|
+
(0, import_react9.useEffect)(() => {
|
|
2191
2529
|
injectKeyframes();
|
|
2192
2530
|
}, []);
|
|
2193
|
-
(0,
|
|
2531
|
+
(0, import_react9.useEffect)(() => {
|
|
2194
2532
|
let mounted = true;
|
|
2195
2533
|
async function startCamera() {
|
|
2196
2534
|
try {
|
|
@@ -2212,12 +2550,12 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2212
2550
|
mounted = false;
|
|
2213
2551
|
};
|
|
2214
2552
|
}, [capturedImage]);
|
|
2215
|
-
(0,
|
|
2553
|
+
(0, import_react9.useEffect)(() => {
|
|
2216
2554
|
return () => {
|
|
2217
2555
|
stream?.getTracks().forEach((t) => t.stop());
|
|
2218
2556
|
};
|
|
2219
2557
|
}, [stream]);
|
|
2220
|
-
const handleCapture = (0,
|
|
2558
|
+
const handleCapture = (0, import_react9.useCallback)(() => {
|
|
2221
2559
|
if (!videoRef.current || !canvasRef.current || isCapturing) return;
|
|
2222
2560
|
setIsCapturing(true);
|
|
2223
2561
|
const video = videoRef.current;
|
|
@@ -2256,22 +2594,22 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2256
2594
|
}
|
|
2257
2595
|
};
|
|
2258
2596
|
if (error) {
|
|
2259
|
-
return /* @__PURE__ */ (0,
|
|
2260
|
-
/* @__PURE__ */ (0,
|
|
2261
|
-
/* @__PURE__ */ (0,
|
|
2597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.errorContainer, children: [
|
|
2598
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.errorText, children: error }),
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { style: styles.primaryButton, onClick: onCancel, children: "Go Back" })
|
|
2262
2600
|
] }) });
|
|
2263
2601
|
}
|
|
2264
2602
|
if (capturedImage) {
|
|
2265
|
-
return /* @__PURE__ */ (0,
|
|
2266
|
-
/* @__PURE__ */ (0,
|
|
2267
|
-
/* @__PURE__ */ (0,
|
|
2268
|
-
/* @__PURE__ */ (0,
|
|
2269
|
-
/* @__PURE__ */ (0,
|
|
2270
|
-
/* @__PURE__ */ (0,
|
|
2603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.darkContainer, children: [
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StepProgressBar, { total: 5, current: 4, isDark: true }),
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.darkScreenHeader, children: [
|
|
2606
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { width: 40 } }),
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { style: styles.darkScreenTitle, children: "Does this look like you?" }),
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2271
2609
|
] }),
|
|
2272
|
-
/* @__PURE__ */ (0,
|
|
2273
|
-
/* @__PURE__ */ (0,
|
|
2274
|
-
/* @__PURE__ */ (0,
|
|
2610
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.darkScreenSubtitle, children: "Check clarity and lighting" }),
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "24px" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { position: "relative" }, children: [
|
|
2612
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { width: "240px", height: "300px", borderRadius: "50%", overflow: "hidden", border: `3px solid ${colors.teal}` }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2275
2613
|
"img",
|
|
2276
2614
|
{
|
|
2277
2615
|
src: capturedImage,
|
|
@@ -2279,31 +2617,32 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2279
2617
|
style: { width: "100%", height: "100%", objectFit: "cover" }
|
|
2280
2618
|
}
|
|
2281
2619
|
) }),
|
|
2282
|
-
/* @__PURE__ */ (0,
|
|
2283
|
-
/* @__PURE__ */ (0,
|
|
2284
|
-
/* @__PURE__ */ (0,
|
|
2285
|
-
/* @__PURE__ */ (0,
|
|
2286
|
-
/* @__PURE__ */ (0,
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.reviewBadge, children: "\u2713 Face detected" }) }),
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.qualityChecks, children: [
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(QualityCheck2, { label: "Clear" }),
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(QualityCheck2, { label: "Centered" }),
|
|
2624
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(QualityCheck2, { label: "Well-lit" })
|
|
2287
2625
|
] })
|
|
2288
2626
|
] }) }),
|
|
2289
|
-
/* @__PURE__ */ (0,
|
|
2290
|
-
/* @__PURE__ */ (0,
|
|
2291
|
-
/* @__PURE__ */ (0,
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.reviewButtonsRow, children: [
|
|
2628
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { style: { ...styles.darkOutlineButton, flex: 1 }, onClick: handleRetake, children: "Retake" }),
|
|
2629
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { style: { ...styles.primaryButton, flex: 1 }, onClick: handleAccept, children: "Use this" })
|
|
2292
2630
|
] })
|
|
2293
2631
|
] });
|
|
2294
2632
|
}
|
|
2295
|
-
return /* @__PURE__ */ (0,
|
|
2296
|
-
/* @__PURE__ */ (0,
|
|
2297
|
-
/* @__PURE__ */ (0,
|
|
2298
|
-
/* @__PURE__ */ (0,
|
|
2299
|
-
/* @__PURE__ */ (0,
|
|
2300
|
-
/* @__PURE__ */ (0,
|
|
2301
|
-
/* @__PURE__ */ (0,
|
|
2633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.captureContainer, children: [
|
|
2634
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StepProgressBar, { total: 5, current: 4, isDark: true }),
|
|
2635
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.darkScreenHeader, children: [
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { width: 40 } }),
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { flex: 1, textAlign: "center" }, children: [
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { style: { ...styles.darkScreenTitle, margin: 0, fontSize: "24px", fontWeight: 700 }, children: "Face the camera" }),
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.darkScreenSubtitle, children: "Keep a neutral expression" })
|
|
2302
2640
|
] }),
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2641
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2304
2642
|
] }),
|
|
2305
|
-
/* @__PURE__ */ (0,
|
|
2306
|
-
|
|
2643
|
+
showVisualGuides && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "6px 0 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(VisualGuide, { kind: "selfie", size: 56 }) }),
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.cameraContainer, children: [
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2307
2646
|
"video",
|
|
2308
2647
|
{
|
|
2309
2648
|
ref: videoRef,
|
|
@@ -2313,10 +2652,10 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2313
2652
|
style: { ...styles.cameraVideo, transform: "scaleX(-1)" }
|
|
2314
2653
|
}
|
|
2315
2654
|
),
|
|
2316
|
-
/* @__PURE__ */ (0,
|
|
2317
|
-
/* @__PURE__ */ (0,
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.selfieOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.faceGuide, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.rotatingRing }) }) }),
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("canvas", { ref: canvasRef, style: { display: "none" } })
|
|
2318
2657
|
] }),
|
|
2319
|
-
/* @__PURE__ */ (0,
|
|
2658
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { textAlign: "center", padding: "8px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2320
2659
|
"span",
|
|
2321
2660
|
{
|
|
2322
2661
|
style: {
|
|
@@ -2325,32 +2664,88 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2325
2664
|
color: colors.teal
|
|
2326
2665
|
},
|
|
2327
2666
|
children: [
|
|
2328
|
-
/* @__PURE__ */ (0,
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { ...styles.pulsingDot, backgroundColor: colors.teal } }),
|
|
2329
2668
|
"Position your face in the oval"
|
|
2330
2669
|
]
|
|
2331
2670
|
}
|
|
2332
2671
|
) }),
|
|
2333
|
-
/* @__PURE__ */ (0,
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.captureFooter, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2334
2673
|
"button",
|
|
2335
2674
|
{
|
|
2336
2675
|
style: { ...styles.captureButton, opacity: isCapturing ? 0.5 : 1 },
|
|
2337
2676
|
onClick: handleCapture,
|
|
2338
2677
|
disabled: isCapturing,
|
|
2339
|
-
children: /* @__PURE__ */ (0,
|
|
2678
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.captureButtonInner })
|
|
2340
2679
|
}
|
|
2341
2680
|
) })
|
|
2342
2681
|
] });
|
|
2343
2682
|
}
|
|
2344
2683
|
function QualityCheck2({ label }) {
|
|
2345
|
-
return /* @__PURE__ */ (0,
|
|
2346
|
-
/* @__PURE__ */ (0,
|
|
2347
|
-
/* @__PURE__ */ (0,
|
|
2684
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.qualityCheck, children: [
|
|
2685
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.qualityCheckIcon, children: "\u2713" }),
|
|
2686
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.qualityCheckLabel, children: label })
|
|
2348
2687
|
] });
|
|
2349
2688
|
}
|
|
2350
2689
|
|
|
2351
2690
|
// src/components/LivenessScreen.tsx
|
|
2352
|
-
var
|
|
2353
|
-
|
|
2691
|
+
var import_react11 = require("react");
|
|
2692
|
+
|
|
2693
|
+
// src/hooks/useLivenessSignals.ts
|
|
2694
|
+
var import_react10 = require("react");
|
|
2695
|
+
var FRAME_INTERVAL_MS2 = 250;
|
|
2696
|
+
function useLivenessSignals(videoRef) {
|
|
2697
|
+
const [signals, setSignals] = (0, import_react10.useState)({
|
|
2698
|
+
faceDetected: false,
|
|
2699
|
+
detectorActive: false
|
|
2700
|
+
});
|
|
2701
|
+
const detectorRef = (0, import_react10.useRef)(null);
|
|
2702
|
+
const intervalRef = (0, import_react10.useRef)(null);
|
|
2703
|
+
(0, import_react10.useEffect)(() => {
|
|
2704
|
+
let cancelled = false;
|
|
2705
|
+
async function setupDetector() {
|
|
2706
|
+
const NativeFaceDetector = typeof window !== "undefined" && "FaceDetector" in window ? window.FaceDetector : null;
|
|
2707
|
+
if (!NativeFaceDetector) {
|
|
2708
|
+
return;
|
|
2709
|
+
}
|
|
2710
|
+
try {
|
|
2711
|
+
const detector = new NativeFaceDetector({ fastMode: true, maxDetectedFaces: 1 });
|
|
2712
|
+
if (cancelled) return;
|
|
2713
|
+
detectorRef.current = detector;
|
|
2714
|
+
setSignals((prev) => ({ ...prev, detectorActive: true }));
|
|
2715
|
+
} catch {
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
intervalRef.current = setInterval(async () => {
|
|
2719
|
+
const detector = detectorRef.current;
|
|
2720
|
+
const video = videoRef.current;
|
|
2721
|
+
if (!detector || !video || video.readyState < 2) return;
|
|
2722
|
+
try {
|
|
2723
|
+
const faces = await detector.detect(video);
|
|
2724
|
+
if (cancelled) return;
|
|
2725
|
+
setSignals((prev) => {
|
|
2726
|
+
const next = faces.length > 0;
|
|
2727
|
+
if (prev.faceDetected === next) return prev;
|
|
2728
|
+
return { ...prev, faceDetected: next };
|
|
2729
|
+
});
|
|
2730
|
+
} catch {
|
|
2731
|
+
}
|
|
2732
|
+
}, FRAME_INTERVAL_MS2);
|
|
2733
|
+
}
|
|
2734
|
+
setupDetector();
|
|
2735
|
+
return () => {
|
|
2736
|
+
cancelled = true;
|
|
2737
|
+
if (intervalRef.current) {
|
|
2738
|
+
clearInterval(intervalRef.current);
|
|
2739
|
+
intervalRef.current = null;
|
|
2740
|
+
}
|
|
2741
|
+
detectorRef.current = null;
|
|
2742
|
+
};
|
|
2743
|
+
}, [videoRef]);
|
|
2744
|
+
return signals;
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
// src/components/LivenessScreen.tsx
|
|
2748
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2354
2749
|
function LivenessScreen({
|
|
2355
2750
|
session,
|
|
2356
2751
|
currentChallenge,
|
|
@@ -2358,22 +2753,25 @@ function LivenessScreen({
|
|
|
2358
2753
|
onChallengeComplete,
|
|
2359
2754
|
onStart,
|
|
2360
2755
|
onComplete,
|
|
2361
|
-
onCancel
|
|
2756
|
+
onCancel,
|
|
2757
|
+
lastChallengeError,
|
|
2758
|
+
showVisualGuides = true
|
|
2362
2759
|
}) {
|
|
2363
|
-
const videoRef = (0,
|
|
2364
|
-
const canvasRef = (0,
|
|
2365
|
-
const [stream, setStream] = (0,
|
|
2366
|
-
const
|
|
2367
|
-
const [
|
|
2368
|
-
const [
|
|
2369
|
-
const [
|
|
2370
|
-
(0,
|
|
2760
|
+
const videoRef = (0, import_react11.useRef)(null);
|
|
2761
|
+
const canvasRef = (0, import_react11.useRef)(null);
|
|
2762
|
+
const [stream, setStream] = (0, import_react11.useState)(null);
|
|
2763
|
+
const livenessSignals = useLivenessSignals(videoRef);
|
|
2764
|
+
const [cameraError, setCameraError] = (0, import_react11.useState)(null);
|
|
2765
|
+
const [phase, setPhase] = (0, import_react11.useState)("preparing");
|
|
2766
|
+
const [countdown, setCountdown] = (0, import_react11.useState)(3);
|
|
2767
|
+
const [capturing, setCapturing] = (0, import_react11.useState)(false);
|
|
2768
|
+
(0, import_react11.useEffect)(() => {
|
|
2371
2769
|
injectKeyframes();
|
|
2372
2770
|
}, []);
|
|
2373
|
-
(0,
|
|
2771
|
+
(0, import_react11.useEffect)(() => {
|
|
2374
2772
|
if (!session) onStart();
|
|
2375
2773
|
}, [session, onStart]);
|
|
2376
|
-
(0,
|
|
2774
|
+
(0, import_react11.useEffect)(() => {
|
|
2377
2775
|
let mounted = true;
|
|
2378
2776
|
async function startCamera() {
|
|
2379
2777
|
try {
|
|
@@ -2405,17 +2803,17 @@ function LivenessScreen({
|
|
|
2405
2803
|
mounted = false;
|
|
2406
2804
|
};
|
|
2407
2805
|
}, []);
|
|
2408
|
-
(0,
|
|
2806
|
+
(0, import_react11.useEffect)(() => {
|
|
2409
2807
|
return () => {
|
|
2410
2808
|
stream?.getTracks().forEach((t) => t.stop());
|
|
2411
2809
|
};
|
|
2412
2810
|
}, [stream]);
|
|
2413
|
-
(0,
|
|
2811
|
+
(0, import_react11.useEffect)(() => {
|
|
2414
2812
|
if (!currentChallenge) return;
|
|
2415
2813
|
setPhase("preparing");
|
|
2416
2814
|
setCountdown(3);
|
|
2417
2815
|
}, [currentChallenge?.id]);
|
|
2418
|
-
const captureFrame = (0,
|
|
2816
|
+
const captureFrame = (0, import_react11.useCallback)(async () => {
|
|
2419
2817
|
if (!currentChallenge || !videoRef.current || !canvasRef.current || capturing) {
|
|
2420
2818
|
return;
|
|
2421
2819
|
}
|
|
@@ -2438,7 +2836,7 @@ function LivenessScreen({
|
|
|
2438
2836
|
0.85
|
|
2439
2837
|
);
|
|
2440
2838
|
}, [currentChallenge, capturing, onChallengeComplete]);
|
|
2441
|
-
(0,
|
|
2839
|
+
(0, import_react11.useEffect)(() => {
|
|
2442
2840
|
if (!currentChallenge || capturing) return;
|
|
2443
2841
|
if (countdown === 0) {
|
|
2444
2842
|
if (phase === "preparing") {
|
|
@@ -2452,32 +2850,32 @@ function LivenessScreen({
|
|
|
2452
2850
|
const t = setTimeout(() => setCountdown((c) => c - 1), 1e3);
|
|
2453
2851
|
return () => clearTimeout(t);
|
|
2454
2852
|
}, [countdown, currentChallenge?.id, capturing, captureFrame, phase]);
|
|
2455
|
-
(0,
|
|
2853
|
+
(0, import_react11.useEffect)(() => {
|
|
2456
2854
|
if (session && !currentChallenge && completedChallenges > 0) {
|
|
2457
2855
|
onComplete();
|
|
2458
2856
|
}
|
|
2459
2857
|
}, [session, currentChallenge, completedChallenges, onComplete]);
|
|
2460
2858
|
if (cameraError) {
|
|
2461
|
-
return /* @__PURE__ */ (0,
|
|
2462
|
-
/* @__PURE__ */ (0,
|
|
2463
|
-
/* @__PURE__ */ (0,
|
|
2859
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: styles.darkContainer, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.errorContainer, children: [
|
|
2860
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.errorText, children: cameraError }),
|
|
2861
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { style: styles.primaryButton, onClick: onCancel, children: "Go back" })
|
|
2464
2862
|
] }) });
|
|
2465
2863
|
}
|
|
2466
2864
|
if (!session) {
|
|
2467
|
-
return /* @__PURE__ */ (0,
|
|
2468
|
-
/* @__PURE__ */ (0,
|
|
2469
|
-
/* @__PURE__ */ (0,
|
|
2865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: styles.darkContainer, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.loadingContainer, children: [
|
|
2866
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: styles.spinner }),
|
|
2867
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { ...styles.loadingText, color: "rgba(255,255,255,0.6)" }, children: "Starting liveness check..." })
|
|
2470
2868
|
] }) });
|
|
2471
2869
|
}
|
|
2472
2870
|
const totalChallenges = session.challenges.length;
|
|
2473
|
-
return /* @__PURE__ */ (0,
|
|
2474
|
-
/* @__PURE__ */ (0,
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
2476
|
-
/* @__PURE__ */ (0,
|
|
2477
|
-
/* @__PURE__ */ (0,
|
|
2478
|
-
/* @__PURE__ */ (0,
|
|
2871
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.captureContainer, children: [
|
|
2872
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StepProgressBar, { total: 5, current: 5, isDark: true }),
|
|
2873
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.darkScreenHeader, children: [
|
|
2874
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { width: 40 } }),
|
|
2875
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: styles.darkScreenTitle, children: "Liveness Check" }),
|
|
2876
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2479
2877
|
] }),
|
|
2480
|
-
/* @__PURE__ */ (0,
|
|
2878
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2481
2879
|
"div",
|
|
2482
2880
|
{
|
|
2483
2881
|
style: {
|
|
@@ -2490,8 +2888,8 @@ function LivenessScreen({
|
|
|
2490
2888
|
padding: "16px 0"
|
|
2491
2889
|
},
|
|
2492
2890
|
children: [
|
|
2493
|
-
/* @__PURE__ */ (0,
|
|
2494
|
-
/* @__PURE__ */ (0,
|
|
2891
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { position: "relative" }, children: [
|
|
2892
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2495
2893
|
"div",
|
|
2496
2894
|
{
|
|
2497
2895
|
style: {
|
|
@@ -2502,7 +2900,7 @@ function LivenessScreen({
|
|
|
2502
2900
|
backgroundColor: "#000",
|
|
2503
2901
|
border: "3px solid rgba(255,255,255,0.2)"
|
|
2504
2902
|
},
|
|
2505
|
-
children: /* @__PURE__ */ (0,
|
|
2903
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2506
2904
|
"video",
|
|
2507
2905
|
{
|
|
2508
2906
|
ref: videoRef,
|
|
@@ -2519,7 +2917,7 @@ function LivenessScreen({
|
|
|
2519
2917
|
)
|
|
2520
2918
|
}
|
|
2521
2919
|
),
|
|
2522
|
-
/* @__PURE__ */ (0,
|
|
2920
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2523
2921
|
"svg",
|
|
2524
2922
|
{
|
|
2525
2923
|
style: {
|
|
@@ -2531,7 +2929,7 @@ function LivenessScreen({
|
|
|
2531
2929
|
width: "256",
|
|
2532
2930
|
height: "316",
|
|
2533
2931
|
viewBox: "0 0 256 316",
|
|
2534
|
-
children: /* @__PURE__ */ (0,
|
|
2932
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2535
2933
|
"ellipse",
|
|
2536
2934
|
{
|
|
2537
2935
|
cx: "128",
|
|
@@ -2547,9 +2945,30 @@ function LivenessScreen({
|
|
|
2547
2945
|
}
|
|
2548
2946
|
)
|
|
2549
2947
|
}
|
|
2948
|
+
),
|
|
2949
|
+
livenessSignals.detectorActive && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2950
|
+
"div",
|
|
2951
|
+
{
|
|
2952
|
+
style: {
|
|
2953
|
+
position: "absolute",
|
|
2954
|
+
bottom: "-32px",
|
|
2955
|
+
left: "50%",
|
|
2956
|
+
transform: "translateX(-50%)",
|
|
2957
|
+
padding: "6px 14px",
|
|
2958
|
+
borderRadius: "999px",
|
|
2959
|
+
fontSize: "12px",
|
|
2960
|
+
fontWeight: 600,
|
|
2961
|
+
color: livenessSignals.faceDetected ? colors.success : "rgba(255,255,255,0.55)",
|
|
2962
|
+
backgroundColor: livenessSignals.faceDetected ? "rgba(16,185,129,0.15)" : "rgba(255,255,255,0.06)",
|
|
2963
|
+
border: livenessSignals.faceDetected ? "1px solid rgba(16,185,129,0.4)" : "1px solid rgba(255,255,255,0.12)",
|
|
2964
|
+
transition: "all 200ms",
|
|
2965
|
+
whiteSpace: "nowrap"
|
|
2966
|
+
},
|
|
2967
|
+
children: livenessSignals.faceDetected ? "\u2713 Face detected" : "Position your face in the oval"
|
|
2968
|
+
}
|
|
2550
2969
|
)
|
|
2551
2970
|
] }),
|
|
2552
|
-
currentChallenge && /* @__PURE__ */ (0,
|
|
2971
|
+
currentChallenge && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2553
2972
|
"div",
|
|
2554
2973
|
{
|
|
2555
2974
|
style: {
|
|
@@ -2562,7 +2981,14 @@ function LivenessScreen({
|
|
|
2562
2981
|
transition: "background-color 200ms, border-color 200ms"
|
|
2563
2982
|
},
|
|
2564
2983
|
children: [
|
|
2565
|
-
/* @__PURE__ */ (0,
|
|
2984
|
+
showVisualGuides && visualGuideForChallenge(currentChallenge.type) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { display: "flex", justifyContent: "center", marginBottom: "12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2985
|
+
VisualGuide,
|
|
2986
|
+
{
|
|
2987
|
+
kind: visualGuideForChallenge(currentChallenge.type),
|
|
2988
|
+
size: 64
|
|
2989
|
+
}
|
|
2990
|
+
) }),
|
|
2991
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2566
2992
|
"p",
|
|
2567
2993
|
{
|
|
2568
2994
|
style: {
|
|
@@ -2576,7 +3002,7 @@ function LivenessScreen({
|
|
|
2576
3002
|
children: capturing ? "Checking..." : phase === "preparing" ? "Get ready" : "Now \u2014 hold the pose"
|
|
2577
3003
|
}
|
|
2578
3004
|
),
|
|
2579
|
-
/* @__PURE__ */ (0,
|
|
3005
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2580
3006
|
"h2",
|
|
2581
3007
|
{
|
|
2582
3008
|
style: {
|
|
@@ -2587,7 +3013,7 @@ function LivenessScreen({
|
|
|
2587
3013
|
children: currentChallenge.instruction
|
|
2588
3014
|
}
|
|
2589
3015
|
),
|
|
2590
|
-
!capturing && /* @__PURE__ */ (0,
|
|
3016
|
+
!capturing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2591
3017
|
"p",
|
|
2592
3018
|
{
|
|
2593
3019
|
style: {
|
|
@@ -2599,16 +3025,33 @@ function LivenessScreen({
|
|
|
2599
3025
|
},
|
|
2600
3026
|
children: countdown
|
|
2601
3027
|
}
|
|
3028
|
+
),
|
|
3029
|
+
lastChallengeError && phase === "preparing" && !capturing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3030
|
+
"p",
|
|
3031
|
+
{
|
|
3032
|
+
style: {
|
|
3033
|
+
margin: "14px 0 0",
|
|
3034
|
+
padding: "10px 12px",
|
|
3035
|
+
borderRadius: "10px",
|
|
3036
|
+
fontSize: "13px",
|
|
3037
|
+
fontWeight: 500,
|
|
3038
|
+
color: "#fca5a5",
|
|
3039
|
+
backgroundColor: "rgba(239,68,68,0.10)",
|
|
3040
|
+
border: "1px solid rgba(239,68,68,0.25)",
|
|
3041
|
+
lineHeight: 1.35
|
|
3042
|
+
},
|
|
3043
|
+
children: lastChallengeError
|
|
3044
|
+
}
|
|
2602
3045
|
)
|
|
2603
3046
|
]
|
|
2604
3047
|
}
|
|
2605
3048
|
),
|
|
2606
|
-
/* @__PURE__ */ (0,
|
|
3049
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("canvas", { ref: canvasRef, style: { display: "none" } })
|
|
2607
3050
|
]
|
|
2608
3051
|
}
|
|
2609
3052
|
),
|
|
2610
|
-
/* @__PURE__ */ (0,
|
|
2611
|
-
/* @__PURE__ */ (0,
|
|
3053
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { padding: "16px 0" }, children: [
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: styles.progressDots, children: session.challenges.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2612
3055
|
"div",
|
|
2613
3056
|
{
|
|
2614
3057
|
style: {
|
|
@@ -2618,7 +3061,7 @@ function LivenessScreen({
|
|
|
2618
3061
|
},
|
|
2619
3062
|
index
|
|
2620
3063
|
)) }),
|
|
2621
|
-
/* @__PURE__ */ (0,
|
|
3064
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { style: styles.progressText, children: [
|
|
2622
3065
|
"Challenge ",
|
|
2623
3066
|
Math.min(completedChallenges + 1, totalChallenges),
|
|
2624
3067
|
" of",
|
|
@@ -2626,7 +3069,7 @@ function LivenessScreen({
|
|
|
2626
3069
|
totalChallenges
|
|
2627
3070
|
] })
|
|
2628
3071
|
] }),
|
|
2629
|
-
/* @__PURE__ */ (0,
|
|
3072
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { padding: "0 24px 24px", textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2630
3073
|
"p",
|
|
2631
3074
|
{
|
|
2632
3075
|
style: {
|
|
@@ -2641,35 +3084,35 @@ function LivenessScreen({
|
|
|
2641
3084
|
}
|
|
2642
3085
|
|
|
2643
3086
|
// src/components/ResultScreen.tsx
|
|
2644
|
-
var
|
|
3087
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2645
3088
|
function ResultScreen({ verification, onDone, onRetry, resultPageMode, simplified, customMessages }) {
|
|
2646
3089
|
const { status } = verification;
|
|
2647
3090
|
const effectiveMode = resultPageMode ?? (simplified ? "simplified" : "detailed");
|
|
2648
3091
|
if (effectiveMode === "simplified") {
|
|
2649
3092
|
switch (status) {
|
|
2650
3093
|
case "approved":
|
|
2651
|
-
return /* @__PURE__ */ (0,
|
|
3094
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SimplifiedSuccess, { onDone, customMessages });
|
|
2652
3095
|
case "rejected":
|
|
2653
|
-
return /* @__PURE__ */ (0,
|
|
3096
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SimplifiedFailed, { onRetry: onRetry || onDone, customMessages });
|
|
2654
3097
|
case "review_required":
|
|
2655
|
-
return /* @__PURE__ */ (0,
|
|
3098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SimplifiedReview, { verification, onDone, customMessages });
|
|
2656
3099
|
case "expired":
|
|
2657
|
-
return /* @__PURE__ */ (0,
|
|
3100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SimplifiedFailed, { onRetry: onRetry || onDone, customMessages: { failedTitle: "Document Expired", failedMessage: "The document you submitted has expired. Please use a valid document." } });
|
|
2658
3101
|
default:
|
|
2659
|
-
return /* @__PURE__ */ (0,
|
|
3102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SimplifiedSuccess, { onDone, customMessages });
|
|
2660
3103
|
}
|
|
2661
3104
|
}
|
|
2662
3105
|
switch (status) {
|
|
2663
3106
|
case "approved":
|
|
2664
|
-
return /* @__PURE__ */ (0,
|
|
3107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SuccessResult, { verification, onDone });
|
|
2665
3108
|
case "rejected":
|
|
2666
|
-
return /* @__PURE__ */ (0,
|
|
3109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RejectedResult, { verification, onRetry: onRetry || onDone });
|
|
2667
3110
|
case "expired":
|
|
2668
|
-
return /* @__PURE__ */ (0,
|
|
3111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ExpiredResult, { verification, onRetry: onRetry || onDone });
|
|
2669
3112
|
case "review_required":
|
|
2670
|
-
return /* @__PURE__ */ (0,
|
|
3113
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ManualReviewResult, { verification, onDone });
|
|
2671
3114
|
default:
|
|
2672
|
-
return /* @__PURE__ */ (0,
|
|
3115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SuccessResult, { verification, onDone });
|
|
2673
3116
|
}
|
|
2674
3117
|
}
|
|
2675
3118
|
function SuccessResult({ verification, onDone }) {
|
|
@@ -2677,16 +3120,16 @@ function SuccessResult({ verification, onDone }) {
|
|
|
2677
3120
|
verification.scores?.overall ?? 100 - (verification.riskScore ?? 16)
|
|
2678
3121
|
);
|
|
2679
3122
|
const metrics = computeScoreBreakdown(verification);
|
|
2680
|
-
return /* @__PURE__ */ (0,
|
|
2681
|
-
/* @__PURE__ */ (0,
|
|
2682
|
-
/* @__PURE__ */ (0,
|
|
3123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3124
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContent, children: [
|
|
3125
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2683
3126
|
"div",
|
|
2684
3127
|
{
|
|
2685
3128
|
style: {
|
|
2686
3129
|
...styles.resultIconOuterRing,
|
|
2687
3130
|
backgroundColor: `${colors.success}15`
|
|
2688
3131
|
},
|
|
2689
|
-
children: /* @__PURE__ */ (0,
|
|
3132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2690
3133
|
"div",
|
|
2691
3134
|
{
|
|
2692
3135
|
style: {
|
|
@@ -2700,9 +3143,9 @@ function SuccessResult({ verification, onDone }) {
|
|
|
2700
3143
|
)
|
|
2701
3144
|
}
|
|
2702
3145
|
),
|
|
2703
|
-
/* @__PURE__ */ (0,
|
|
2704
|
-
/* @__PURE__ */ (0,
|
|
2705
|
-
/* @__PURE__ */ (0,
|
|
3146
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.resultTitle, children: "Verification approved" }),
|
|
3147
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.resultSubtitle, children: "Your identity has been successfully verified." }),
|
|
3148
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2706
3149
|
ScoreCard,
|
|
2707
3150
|
{
|
|
2708
3151
|
score,
|
|
@@ -2710,9 +3153,9 @@ function SuccessResult({ verification, onDone }) {
|
|
|
2710
3153
|
gradient: `linear-gradient(135deg, ${colors.teal}, ${colors.tealDark})`
|
|
2711
3154
|
}
|
|
2712
3155
|
),
|
|
2713
|
-
metrics.map((m, i) => /* @__PURE__ */ (0,
|
|
3156
|
+
metrics.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScoreMetricRow, { ...m }, i))
|
|
2714
3157
|
] }),
|
|
2715
|
-
/* @__PURE__ */ (0,
|
|
3158
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onDone, children: "Done" }) })
|
|
2716
3159
|
] });
|
|
2717
3160
|
}
|
|
2718
3161
|
function RejectedResult({ verification, onRetry }) {
|
|
@@ -2720,16 +3163,16 @@ function RejectedResult({ verification, onRetry }) {
|
|
|
2720
3163
|
verification.scores?.overall ?? 100 - (verification.riskScore ?? 58)
|
|
2721
3164
|
);
|
|
2722
3165
|
const metrics = computeScoreBreakdown(verification);
|
|
2723
|
-
return /* @__PURE__ */ (0,
|
|
2724
|
-
/* @__PURE__ */ (0,
|
|
2725
|
-
/* @__PURE__ */ (0,
|
|
3166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3167
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContent, children: [
|
|
3168
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2726
3169
|
"div",
|
|
2727
3170
|
{
|
|
2728
3171
|
style: {
|
|
2729
3172
|
...styles.resultIconOuterRing,
|
|
2730
3173
|
backgroundColor: `${colors.error}15`
|
|
2731
3174
|
},
|
|
2732
|
-
children: /* @__PURE__ */ (0,
|
|
3175
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2733
3176
|
"div",
|
|
2734
3177
|
{
|
|
2735
3178
|
style: {
|
|
@@ -2743,9 +3186,9 @@ function RejectedResult({ verification, onRetry }) {
|
|
|
2743
3186
|
)
|
|
2744
3187
|
}
|
|
2745
3188
|
),
|
|
2746
|
-
/* @__PURE__ */ (0,
|
|
2747
|
-
/* @__PURE__ */ (0,
|
|
2748
|
-
/* @__PURE__ */ (0,
|
|
3189
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.resultTitle, children: "Verification rejected" }),
|
|
3190
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.resultSubtitle, children: "We could not verify your identity. Please try again with a valid document." }),
|
|
3191
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2749
3192
|
ScoreCard,
|
|
2750
3193
|
{
|
|
2751
3194
|
score,
|
|
@@ -2753,15 +3196,15 @@ function RejectedResult({ verification, onRetry }) {
|
|
|
2753
3196
|
gradient: `linear-gradient(135deg, ${colors.error}, #B91C1C)`
|
|
2754
3197
|
}
|
|
2755
3198
|
),
|
|
2756
|
-
metrics.map((m, i) => /* @__PURE__ */ (0,
|
|
3199
|
+
metrics.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScoreMetricRow, { ...m }, i))
|
|
2757
3200
|
] }),
|
|
2758
|
-
/* @__PURE__ */ (0,
|
|
3201
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onRetry, children: "Try again" }) })
|
|
2759
3202
|
] });
|
|
2760
3203
|
}
|
|
2761
3204
|
function ExpiredResult({ verification, onRetry }) {
|
|
2762
|
-
return /* @__PURE__ */ (0,
|
|
2763
|
-
/* @__PURE__ */ (0,
|
|
2764
|
-
/* @__PURE__ */ (0,
|
|
3205
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3206
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContent, children: [
|
|
3207
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2765
3208
|
"div",
|
|
2766
3209
|
{
|
|
2767
3210
|
style: {
|
|
@@ -2769,7 +3212,7 @@ function ExpiredResult({ verification, onRetry }) {
|
|
|
2769
3212
|
backgroundColor: `${colors.warning}15`,
|
|
2770
3213
|
border: `2px solid ${colors.warning}30`
|
|
2771
3214
|
},
|
|
2772
|
-
children: /* @__PURE__ */ (0,
|
|
3215
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2773
3216
|
"div",
|
|
2774
3217
|
{
|
|
2775
3218
|
style: {
|
|
@@ -2783,29 +3226,29 @@ function ExpiredResult({ verification, onRetry }) {
|
|
|
2783
3226
|
)
|
|
2784
3227
|
}
|
|
2785
3228
|
),
|
|
2786
|
-
/* @__PURE__ */ (0,
|
|
2787
|
-
/* @__PURE__ */ (0,
|
|
2788
|
-
verification.documentVerification && /* @__PURE__ */ (0,
|
|
2789
|
-
/* @__PURE__ */ (0,
|
|
2790
|
-
/* @__PURE__ */ (0,
|
|
2791
|
-
/* @__PURE__ */ (0,
|
|
3229
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.resultTitle, children: "Document expired" }),
|
|
3230
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.resultSubtitle, children: "The document you submitted has expired. Please use a valid, non-expired document." }),
|
|
3231
|
+
verification.documentVerification && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.expiryCard, children: [
|
|
3232
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.expiryRow, children: [
|
|
3233
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.expiryLabel, children: "Document type" }),
|
|
3234
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.expiryValue, children: verification.documentVerification.documentType || "ID Card" })
|
|
2792
3235
|
] }),
|
|
2793
|
-
verification.documentVerification.issuingCountry && /* @__PURE__ */ (0,
|
|
2794
|
-
/* @__PURE__ */ (0,
|
|
2795
|
-
/* @__PURE__ */ (0,
|
|
3236
|
+
verification.documentVerification.issuingCountry && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.expiryRow, children: [
|
|
3237
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.expiryLabel, children: "Country" }),
|
|
3238
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.expiryValue, children: verification.documentVerification.issuingCountry })
|
|
2796
3239
|
] }),
|
|
2797
|
-
verification.documentVerification.expirationDate && /* @__PURE__ */ (0,
|
|
2798
|
-
/* @__PURE__ */ (0,
|
|
2799
|
-
/* @__PURE__ */ (0,
|
|
3240
|
+
verification.documentVerification.expirationDate && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.expiryRow, children: [
|
|
3241
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.expiryLabel, children: "Expired on" }),
|
|
3242
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.expiryBadge, children: verification.documentVerification.expirationDate })
|
|
2800
3243
|
] })
|
|
2801
3244
|
] }),
|
|
2802
|
-
/* @__PURE__ */ (0,
|
|
2803
|
-
/* @__PURE__ */ (0,
|
|
2804
|
-
/* @__PURE__ */ (0,
|
|
2805
|
-
/* @__PURE__ */ (0,
|
|
3245
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { textAlign: "left" }, children: [
|
|
3246
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GuidanceTip, { number: 1, text: "Check the expiration date on your document" }),
|
|
3247
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GuidanceTip, { number: 2, text: "Use a different document that is currently valid" }),
|
|
3248
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GuidanceTip, { number: 3, text: "Ensure the document details are clearly visible" })
|
|
2806
3249
|
] })
|
|
2807
3250
|
] }),
|
|
2808
|
-
/* @__PURE__ */ (0,
|
|
3251
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onRetry, children: "Try with a valid document" }) })
|
|
2809
3252
|
] });
|
|
2810
3253
|
}
|
|
2811
3254
|
function ManualReviewResult({ verification, onDone }) {
|
|
@@ -2813,9 +3256,9 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2813
3256
|
verification.scores?.overall ?? 100 - (verification.riskScore ?? 32)
|
|
2814
3257
|
);
|
|
2815
3258
|
const metrics = computeScoreBreakdown(verification);
|
|
2816
|
-
return /* @__PURE__ */ (0,
|
|
2817
|
-
/* @__PURE__ */ (0,
|
|
2818
|
-
/* @__PURE__ */ (0,
|
|
3259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3260
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContent, children: [
|
|
3261
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2819
3262
|
"div",
|
|
2820
3263
|
{
|
|
2821
3264
|
style: {
|
|
@@ -2823,7 +3266,7 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2823
3266
|
backgroundColor: `${colors.info}15`,
|
|
2824
3267
|
border: `2px solid ${colors.info}30`
|
|
2825
3268
|
},
|
|
2826
|
-
children: /* @__PURE__ */ (0,
|
|
3269
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2827
3270
|
"div",
|
|
2828
3271
|
{
|
|
2829
3272
|
style: {
|
|
@@ -2837,9 +3280,9 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2837
3280
|
)
|
|
2838
3281
|
}
|
|
2839
3282
|
),
|
|
2840
|
-
/* @__PURE__ */ (0,
|
|
2841
|
-
/* @__PURE__ */ (0,
|
|
2842
|
-
/* @__PURE__ */ (0,
|
|
3283
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.resultTitle, children: "Under review" }),
|
|
3284
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.resultSubtitle, children: "Your verification requires manual review. We'll notify you of the result." }),
|
|
3285
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2843
3286
|
ScoreCard,
|
|
2844
3287
|
{
|
|
2845
3288
|
score,
|
|
@@ -2847,21 +3290,21 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2847
3290
|
gradient: `linear-gradient(135deg, ${colors.info}, #0369A1)`
|
|
2848
3291
|
}
|
|
2849
3292
|
),
|
|
2850
|
-
metrics.map((m, i) => /* @__PURE__ */ (0,
|
|
3293
|
+
metrics.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScoreMetricRow, { ...m }, i))
|
|
2851
3294
|
] }),
|
|
2852
|
-
/* @__PURE__ */ (0,
|
|
3295
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onDone, children: "Got it" }) })
|
|
2853
3296
|
] });
|
|
2854
3297
|
}
|
|
2855
3298
|
function GuidanceTip({ number, text }) {
|
|
2856
|
-
return /* @__PURE__ */ (0,
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
2858
|
-
/* @__PURE__ */ (0,
|
|
3299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.guidanceTip, children: [
|
|
3300
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.guidanceTipNumber, children: number }),
|
|
3301
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.guidanceTipText, children: text })
|
|
2859
3302
|
] });
|
|
2860
3303
|
}
|
|
2861
3304
|
function SimplifiedSuccess({ onDone, customMessages }) {
|
|
2862
|
-
return /* @__PURE__ */ (0,
|
|
2863
|
-
/* @__PURE__ */ (0,
|
|
2864
|
-
/* @__PURE__ */ (0,
|
|
3305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3306
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { ...styles.resultContent, textAlign: "center" }, children: [
|
|
3307
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2865
3308
|
"div",
|
|
2866
3309
|
{
|
|
2867
3310
|
style: {
|
|
@@ -2870,7 +3313,7 @@ function SimplifiedSuccess({ onDone, customMessages }) {
|
|
|
2870
3313
|
width: 96,
|
|
2871
3314
|
height: 96
|
|
2872
3315
|
},
|
|
2873
|
-
children: /* @__PURE__ */ (0,
|
|
3316
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2874
3317
|
"div",
|
|
2875
3318
|
{
|
|
2876
3319
|
style: {
|
|
@@ -2887,16 +3330,16 @@ function SimplifiedSuccess({ onDone, customMessages }) {
|
|
|
2887
3330
|
)
|
|
2888
3331
|
}
|
|
2889
3332
|
),
|
|
2890
|
-
/* @__PURE__ */ (0,
|
|
2891
|
-
/* @__PURE__ */ (0,
|
|
3333
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: { ...styles.resultTitle, fontSize: 24, marginTop: 16 }, children: customMessages?.successTitle || "Verification Successful" }),
|
|
3334
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { ...styles.resultSubtitle, fontSize: 16, maxWidth: 320, margin: "8px auto 0" }, children: customMessages?.successMessage || "Your identity has been successfully verified. You can now proceed." })
|
|
2892
3335
|
] }),
|
|
2893
|
-
/* @__PURE__ */ (0,
|
|
3336
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onDone, children: "Continue" }) })
|
|
2894
3337
|
] });
|
|
2895
3338
|
}
|
|
2896
3339
|
function SimplifiedFailed({ onRetry, customMessages }) {
|
|
2897
|
-
return /* @__PURE__ */ (0,
|
|
2898
|
-
/* @__PURE__ */ (0,
|
|
2899
|
-
/* @__PURE__ */ (0,
|
|
3340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3341
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { ...styles.resultContent, textAlign: "center" }, children: [
|
|
3342
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2900
3343
|
"div",
|
|
2901
3344
|
{
|
|
2902
3345
|
style: {
|
|
@@ -2905,7 +3348,7 @@ function SimplifiedFailed({ onRetry, customMessages }) {
|
|
|
2905
3348
|
width: 96,
|
|
2906
3349
|
height: 96
|
|
2907
3350
|
},
|
|
2908
|
-
children: /* @__PURE__ */ (0,
|
|
3351
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2909
3352
|
"div",
|
|
2910
3353
|
{
|
|
2911
3354
|
style: {
|
|
@@ -2922,16 +3365,16 @@ function SimplifiedFailed({ onRetry, customMessages }) {
|
|
|
2922
3365
|
)
|
|
2923
3366
|
}
|
|
2924
3367
|
),
|
|
2925
|
-
/* @__PURE__ */ (0,
|
|
2926
|
-
/* @__PURE__ */ (0,
|
|
3368
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: { ...styles.resultTitle, fontSize: 24, marginTop: 16 }, children: customMessages?.failedTitle || "Verification Failed" }),
|
|
3369
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { ...styles.resultSubtitle, fontSize: 16, maxWidth: 320, margin: "8px auto 0" }, children: customMessages?.failedMessage || "We could not verify your identity. Please try again with a valid document." })
|
|
2927
3370
|
] }),
|
|
2928
|
-
/* @__PURE__ */ (0,
|
|
3371
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onRetry, children: "Try Again" }) })
|
|
2929
3372
|
] });
|
|
2930
3373
|
}
|
|
2931
3374
|
function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
2932
|
-
return /* @__PURE__ */ (0,
|
|
2933
|
-
/* @__PURE__ */ (0,
|
|
2934
|
-
/* @__PURE__ */ (0,
|
|
3375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3376
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { ...styles.resultContent, textAlign: "center" }, children: [
|
|
3377
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2935
3378
|
"div",
|
|
2936
3379
|
{
|
|
2937
3380
|
style: {
|
|
@@ -2940,7 +3383,7 @@ function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
|
2940
3383
|
width: 96,
|
|
2941
3384
|
height: 96
|
|
2942
3385
|
},
|
|
2943
|
-
children: /* @__PURE__ */ (0,
|
|
3386
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2944
3387
|
"div",
|
|
2945
3388
|
{
|
|
2946
3389
|
style: {
|
|
@@ -2957,9 +3400,9 @@ function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
|
2957
3400
|
)
|
|
2958
3401
|
}
|
|
2959
3402
|
),
|
|
2960
|
-
/* @__PURE__ */ (0,
|
|
2961
|
-
/* @__PURE__ */ (0,
|
|
2962
|
-
/* @__PURE__ */ (0,
|
|
3403
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: { ...styles.resultTitle, fontSize: 24, marginTop: 16 }, children: customMessages?.reviewTitle || "Verification Under Review" }),
|
|
3404
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { ...styles.resultSubtitle, fontSize: 16, maxWidth: 320, margin: "8px auto 0" }, children: customMessages?.reviewMessage || "Your verification requires additional review. We will notify you of the result." }),
|
|
3405
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: {
|
|
2963
3406
|
marginTop: 24,
|
|
2964
3407
|
padding: "12px 24px",
|
|
2965
3408
|
backgroundColor: `${colors.info}10`,
|
|
@@ -2967,27 +3410,27 @@ function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
|
2967
3410
|
border: `1px solid ${colors.info}30`,
|
|
2968
3411
|
display: "inline-block"
|
|
2969
3412
|
}, children: [
|
|
2970
|
-
/* @__PURE__ */ (0,
|
|
2971
|
-
/* @__PURE__ */ (0,
|
|
3413
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontSize: 12, color: colors.textSecondary }, children: "Reference: " }),
|
|
3414
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontSize: 14, fontWeight: 600, fontFamily: "monospace" }, children: verification.id.slice(0, 8) })
|
|
2972
3415
|
] })
|
|
2973
3416
|
] }),
|
|
2974
|
-
/* @__PURE__ */ (0,
|
|
3417
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.footer, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { style: styles.primaryButton, onClick: onDone, children: "Got It" }) })
|
|
2975
3418
|
] });
|
|
2976
3419
|
}
|
|
2977
3420
|
|
|
2978
3421
|
// src/components/ErrorScreen.tsx
|
|
2979
|
-
var
|
|
3422
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2980
3423
|
function ErrorScreen({ error, onRetry, onCancel }) {
|
|
2981
|
-
return /* @__PURE__ */ (0,
|
|
2982
|
-
/* @__PURE__ */ (0,
|
|
2983
|
-
/* @__PURE__ */ (0,
|
|
3424
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.resultContainer, children: [
|
|
3425
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.resultContent, children: [
|
|
3426
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2984
3427
|
"div",
|
|
2985
3428
|
{
|
|
2986
3429
|
style: {
|
|
2987
3430
|
...styles.resultIconOuterRing,
|
|
2988
3431
|
backgroundColor: colors.errorBg
|
|
2989
3432
|
},
|
|
2990
|
-
children: /* @__PURE__ */ (0,
|
|
3433
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2991
3434
|
"div",
|
|
2992
3435
|
{
|
|
2993
3436
|
style: {
|
|
@@ -3001,26 +3444,26 @@ function ErrorScreen({ error, onRetry, onCancel }) {
|
|
|
3001
3444
|
)
|
|
3002
3445
|
}
|
|
3003
3446
|
),
|
|
3004
|
-
/* @__PURE__ */ (0,
|
|
3005
|
-
/* @__PURE__ */ (0,
|
|
3006
|
-
error.recoverySuggestion && /* @__PURE__ */ (0,
|
|
3447
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { style: styles.resultTitle, children: "Something went wrong" }),
|
|
3448
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.resultSubtitle, children: error.message }),
|
|
3449
|
+
error.recoverySuggestion && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { ...styles.bodyText, marginTop: "12px" }, children: error.recoverySuggestion })
|
|
3007
3450
|
] }),
|
|
3008
|
-
/* @__PURE__ */ (0,
|
|
3009
|
-
error.isRetryable && /* @__PURE__ */ (0,
|
|
3010
|
-
/* @__PURE__ */ (0,
|
|
3451
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.footer, children: [
|
|
3452
|
+
error.isRetryable && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { style: styles.primaryButton, onClick: onRetry, children: "Try Again" }),
|
|
3453
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { style: styles.textButton, onClick: onCancel, children: "Cancel" })
|
|
3011
3454
|
] })
|
|
3012
3455
|
] });
|
|
3013
3456
|
}
|
|
3014
3457
|
|
|
3015
3458
|
// src/components/LoadingScreen.tsx
|
|
3016
|
-
var
|
|
3017
|
-
var
|
|
3459
|
+
var import_react12 = require("react");
|
|
3460
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3018
3461
|
function LoadingScreen({ message = "Loading..." }) {
|
|
3019
|
-
(0,
|
|
3462
|
+
(0, import_react12.useEffect)(() => {
|
|
3020
3463
|
injectKeyframes();
|
|
3021
3464
|
}, []);
|
|
3022
|
-
return /* @__PURE__ */ (0,
|
|
3023
|
-
/* @__PURE__ */ (0,
|
|
3465
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.loadingContainer, children: [
|
|
3466
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3024
3467
|
"div",
|
|
3025
3468
|
{
|
|
3026
3469
|
style: {
|
|
@@ -3037,18 +3480,19 @@ function LoadingScreen({ message = "Loading..." }) {
|
|
|
3037
3480
|
children: "\u{1F6E1}\uFE0F"
|
|
3038
3481
|
}
|
|
3039
3482
|
),
|
|
3040
|
-
/* @__PURE__ */ (0,
|
|
3483
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.loadingText, children: message })
|
|
3041
3484
|
] }) });
|
|
3042
3485
|
}
|
|
3043
3486
|
|
|
3044
3487
|
// src/components/VerificationFlow.tsx
|
|
3045
|
-
var
|
|
3488
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3046
3489
|
function VerificationFlow({
|
|
3047
3490
|
externalId,
|
|
3048
3491
|
tier = "standard",
|
|
3049
3492
|
documentTypes,
|
|
3050
3493
|
expectedFirstName,
|
|
3051
3494
|
expectedLastName,
|
|
3495
|
+
showVisualGuides = true,
|
|
3052
3496
|
onComplete,
|
|
3053
3497
|
onError,
|
|
3054
3498
|
onCancel,
|
|
@@ -3070,20 +3514,20 @@ function VerificationFlow({
|
|
|
3070
3514
|
retry,
|
|
3071
3515
|
sdk
|
|
3072
3516
|
} = useKoraIDV();
|
|
3073
|
-
const [selectedCountry, setSelectedCountry] = (0,
|
|
3074
|
-
const [flowStep, setFlowStep] = (0,
|
|
3075
|
-
const [showFlipInstruction, setShowFlipInstruction] = (0,
|
|
3076
|
-
const [supportedCountries, setSupportedCountries] = (0,
|
|
3077
|
-
const [countriesLoading, setCountriesLoading] = (0,
|
|
3078
|
-
(0,
|
|
3517
|
+
const [selectedCountry, setSelectedCountry] = (0, import_react13.useState)(null);
|
|
3518
|
+
const [flowStep, setFlowStep] = (0, import_react13.useState)("consent");
|
|
3519
|
+
const [showFlipInstruction, setShowFlipInstruction] = (0, import_react13.useState)(true);
|
|
3520
|
+
const [supportedCountries, setSupportedCountries] = (0, import_react13.useState)([]);
|
|
3521
|
+
const [countriesLoading, setCountriesLoading] = (0, import_react13.useState)(false);
|
|
3522
|
+
(0, import_react13.useEffect)(() => {
|
|
3079
3523
|
if (state.step === "document_front") {
|
|
3080
3524
|
setShowFlipInstruction(true);
|
|
3081
3525
|
}
|
|
3082
3526
|
}, [state.step]);
|
|
3083
|
-
(0,
|
|
3527
|
+
(0, import_react13.useEffect)(() => {
|
|
3084
3528
|
startVerification(externalId, tier, expectedFirstName, expectedLastName);
|
|
3085
3529
|
}, [externalId, tier, expectedFirstName, expectedLastName, startVerification]);
|
|
3086
|
-
(0,
|
|
3530
|
+
(0, import_react13.useEffect)(() => {
|
|
3087
3531
|
if (state.error && onError) {
|
|
3088
3532
|
onError(state.error);
|
|
3089
3533
|
}
|
|
@@ -3129,19 +3573,19 @@ function VerificationFlow({
|
|
|
3129
3573
|
...style
|
|
3130
3574
|
};
|
|
3131
3575
|
if (state.error) {
|
|
3132
|
-
return /* @__PURE__ */ (0,
|
|
3576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ErrorScreen, { error: state.error, onRetry: retry, onCancel: handleCancel }) });
|
|
3133
3577
|
}
|
|
3134
3578
|
if (state.isLoading && state.step !== "processing") {
|
|
3135
|
-
return /* @__PURE__ */ (0,
|
|
3579
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LoadingScreen, {}) });
|
|
3136
3580
|
}
|
|
3137
3581
|
if (flowStep === "consent" && state.step === "consent") {
|
|
3138
|
-
return /* @__PURE__ */ (0,
|
|
3582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ConsentScreen, { onAccept: handleAcceptConsent, onDecline: handleCancel }) });
|
|
3139
3583
|
}
|
|
3140
3584
|
if (flowStep === "country_selection") {
|
|
3141
3585
|
if (countriesLoading) {
|
|
3142
|
-
return /* @__PURE__ */ (0,
|
|
3586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LoadingScreen, {}) });
|
|
3143
3587
|
}
|
|
3144
|
-
return /* @__PURE__ */ (0,
|
|
3588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3145
3589
|
CountrySelectionScreen,
|
|
3146
3590
|
{
|
|
3147
3591
|
countries: supportedCountries,
|
|
@@ -3150,8 +3594,8 @@ function VerificationFlow({
|
|
|
3150
3594
|
}
|
|
3151
3595
|
) });
|
|
3152
3596
|
}
|
|
3153
|
-
return /* @__PURE__ */ (0,
|
|
3154
|
-
state.step === "document_selection" && /* @__PURE__ */ (0,
|
|
3597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className, style: containerStyle, children: [
|
|
3598
|
+
state.step === "document_selection" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3155
3599
|
DocumentSelectionScreen,
|
|
3156
3600
|
{
|
|
3157
3601
|
documentTypes,
|
|
@@ -3160,32 +3604,41 @@ function VerificationFlow({
|
|
|
3160
3604
|
onCancel: handleCancel
|
|
3161
3605
|
}
|
|
3162
3606
|
),
|
|
3163
|
-
state.step === "document_front" && /* @__PURE__ */ (0,
|
|
3607
|
+
state.step === "document_front" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3164
3608
|
DocumentCaptureScreen,
|
|
3165
3609
|
{
|
|
3166
3610
|
side: "front",
|
|
3167
3611
|
onQualityCheck: (blob) => checkDocumentQuality(blob),
|
|
3168
3612
|
onCapture: (imageData) => uploadDocument(imageData, "front", selectedCountry?.id),
|
|
3169
|
-
onCancel: handleCancel
|
|
3613
|
+
onCancel: handleCancel,
|
|
3614
|
+
showVisualGuides
|
|
3170
3615
|
}
|
|
3171
3616
|
),
|
|
3172
|
-
state.step === "document_back" && showFlipInstruction && /* @__PURE__ */ (0,
|
|
3617
|
+
state.step === "document_back" && showFlipInstruction && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3173
3618
|
FlipDocumentScreen,
|
|
3174
3619
|
{
|
|
3175
3620
|
onContinue: () => setShowFlipInstruction(false),
|
|
3176
3621
|
onCancel: handleCancel
|
|
3177
3622
|
}
|
|
3178
3623
|
),
|
|
3179
|
-
state.step === "document_back" && !showFlipInstruction && /* @__PURE__ */ (0,
|
|
3624
|
+
state.step === "document_back" && !showFlipInstruction && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3180
3625
|
DocumentCaptureScreen,
|
|
3181
3626
|
{
|
|
3182
3627
|
side: "back",
|
|
3183
3628
|
onCapture: (imageData) => uploadDocument(imageData, "back", selectedCountry?.id),
|
|
3184
|
-
onCancel: handleCancel
|
|
3629
|
+
onCancel: handleCancel,
|
|
3630
|
+
showVisualGuides
|
|
3185
3631
|
}
|
|
3186
3632
|
),
|
|
3187
|
-
state.step === "selfie" && /* @__PURE__ */ (0,
|
|
3188
|
-
|
|
3633
|
+
state.step === "selfie" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3634
|
+
SelfieCaptureScreen,
|
|
3635
|
+
{
|
|
3636
|
+
onCapture: uploadSelfie,
|
|
3637
|
+
onCancel: handleCancel,
|
|
3638
|
+
showVisualGuides
|
|
3639
|
+
}
|
|
3640
|
+
),
|
|
3641
|
+
state.step === "liveness" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3189
3642
|
LivenessScreen,
|
|
3190
3643
|
{
|
|
3191
3644
|
session: state.livenessSession,
|
|
@@ -3194,20 +3647,13 @@ function VerificationFlow({
|
|
|
3194
3647
|
onChallengeComplete: submitChallenge,
|
|
3195
3648
|
onStart: startLiveness,
|
|
3196
3649
|
onComplete: complete,
|
|
3197
|
-
onCancel: handleCancel
|
|
3650
|
+
onCancel: handleCancel,
|
|
3651
|
+
lastChallengeError: state.lastChallengeError,
|
|
3652
|
+
showVisualGuides
|
|
3198
3653
|
}
|
|
3199
3654
|
),
|
|
3200
|
-
state.step === "processing" && /* @__PURE__ */ (0,
|
|
3201
|
-
|
|
3202
|
-
{
|
|
3203
|
-
steps: [
|
|
3204
|
-
{ label: "Document analyzed", status: "done" },
|
|
3205
|
-
{ label: "Checking face match", status: "active" },
|
|
3206
|
-
{ label: "Finalizing results", status: "pending" }
|
|
3207
|
-
]
|
|
3208
|
-
}
|
|
3209
|
-
),
|
|
3210
|
-
state.step === "complete" && state.verification && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3655
|
+
state.step === "processing" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ProcessingScreen, {}),
|
|
3656
|
+
state.step === "complete" && state.verification && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3211
3657
|
ResultScreen,
|
|
3212
3658
|
{
|
|
3213
3659
|
verification: state.verification,
|
|
@@ -3219,8 +3665,8 @@ function VerificationFlow({
|
|
|
3219
3665
|
}
|
|
3220
3666
|
|
|
3221
3667
|
// src/components/QrHandoffScreen.tsx
|
|
3222
|
-
var
|
|
3223
|
-
var
|
|
3668
|
+
var import_react14 = require("react");
|
|
3669
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
3224
3670
|
function QrHandoffScreen({
|
|
3225
3671
|
session,
|
|
3226
3672
|
onMobileCaptureComplete,
|
|
@@ -3229,11 +3675,11 @@ function QrHandoffScreen({
|
|
|
3229
3675
|
onRefresh,
|
|
3230
3676
|
eventSource
|
|
3231
3677
|
}) {
|
|
3232
|
-
const [timeLeft, setTimeLeft] = (0,
|
|
3233
|
-
const [scanned, setScanned] = (0,
|
|
3234
|
-
const [expired, setExpired] = (0,
|
|
3235
|
-
const timerRef = (0,
|
|
3236
|
-
(0,
|
|
3678
|
+
const [timeLeft, setTimeLeft] = (0, import_react14.useState)(session.expiresIn);
|
|
3679
|
+
const [scanned, setScanned] = (0, import_react14.useState)(false);
|
|
3680
|
+
const [expired, setExpired] = (0, import_react14.useState)(false);
|
|
3681
|
+
const timerRef = (0, import_react14.useRef)();
|
|
3682
|
+
(0, import_react14.useEffect)(() => {
|
|
3237
3683
|
setTimeLeft(session.expiresIn);
|
|
3238
3684
|
setExpired(false);
|
|
3239
3685
|
setScanned(false);
|
|
@@ -3250,7 +3696,7 @@ function QrHandoffScreen({
|
|
|
3250
3696
|
}, 1e3);
|
|
3251
3697
|
return () => clearInterval(timerRef.current);
|
|
3252
3698
|
}, [session.token]);
|
|
3253
|
-
(0,
|
|
3699
|
+
(0, import_react14.useEffect)(() => {
|
|
3254
3700
|
if (!eventSource) return;
|
|
3255
3701
|
const handleStatus = (event) => {
|
|
3256
3702
|
try {
|
|
@@ -3276,34 +3722,34 @@ function QrHandoffScreen({
|
|
|
3276
3722
|
const seconds = timeLeft % 60;
|
|
3277
3723
|
const qrSize = 200;
|
|
3278
3724
|
if (expired) {
|
|
3279
|
-
return /* @__PURE__ */ (0,
|
|
3280
|
-
/* @__PURE__ */ (0,
|
|
3281
|
-
/* @__PURE__ */ (0,
|
|
3282
|
-
/* @__PURE__ */ (0,
|
|
3283
|
-
/* @__PURE__ */ (0,
|
|
3284
|
-
/* @__PURE__ */ (0,
|
|
3725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.content, children: [
|
|
3726
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.expiredIcon, children: "\u23F1" }),
|
|
3727
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { style: qrStyles.title, children: "QR Code Expired" }),
|
|
3728
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: qrStyles.subtitle, children: "The QR code has expired. Generate a new one to continue." }),
|
|
3729
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { style: qrStyles.primaryButton, onClick: onRefresh, children: "Generate New QR Code" }),
|
|
3730
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { style: qrStyles.secondaryButton, onClick: onContinueOnDevice, children: "Continue on this device instead" })
|
|
3285
3731
|
] }) });
|
|
3286
3732
|
}
|
|
3287
3733
|
if (scanned) {
|
|
3288
|
-
return /* @__PURE__ */ (0,
|
|
3289
|
-
/* @__PURE__ */ (0,
|
|
3290
|
-
/* @__PURE__ */ (0,
|
|
3291
|
-
/* @__PURE__ */ (0,
|
|
3292
|
-
/* @__PURE__ */ (0,
|
|
3293
|
-
/* @__PURE__ */ (0,
|
|
3734
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.content, children: [
|
|
3735
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.spinnerContainer, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.spinner }) }),
|
|
3736
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { style: qrStyles.title, children: "Capturing on your phone..." }),
|
|
3737
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: qrStyles.subtitle, children: "Complete the document scan and selfie on your mobile device. This page will update automatically when done." }),
|
|
3738
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.statusBadge, children: [
|
|
3739
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: qrStyles.statusDot }),
|
|
3294
3740
|
"Connected \u2014 waiting for capture"
|
|
3295
3741
|
] })
|
|
3296
3742
|
] }) });
|
|
3297
3743
|
}
|
|
3298
|
-
return /* @__PURE__ */ (0,
|
|
3299
|
-
/* @__PURE__ */ (0,
|
|
3300
|
-
/* @__PURE__ */ (0,
|
|
3301
|
-
/* @__PURE__ */ (0,
|
|
3302
|
-
/* @__PURE__ */ (0,
|
|
3744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.content, children: [
|
|
3745
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { style: qrStyles.title, children: "Scan with your phone" }),
|
|
3746
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: qrStyles.subtitle, children: "Use your phone's camera for a better capture experience. Scan the QR code below to continue on your mobile device." }),
|
|
3747
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.qrContainer, children: [
|
|
3748
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: {
|
|
3303
3749
|
...qrStyles.qrBox,
|
|
3304
3750
|
width: qrSize,
|
|
3305
3751
|
height: qrSize
|
|
3306
|
-
}, children: /* @__PURE__ */ (0,
|
|
3752
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3307
3753
|
"img",
|
|
3308
3754
|
{
|
|
3309
3755
|
src: `https://api.qrserver.com/v1/create-qr-code/?size=${qrSize}x${qrSize}&data=${encodeURIComponent(session.captureUrl)}&margin=8`,
|
|
@@ -3313,26 +3759,26 @@ function QrHandoffScreen({
|
|
|
3313
3759
|
style: { borderRadius: 12 }
|
|
3314
3760
|
}
|
|
3315
3761
|
) }),
|
|
3316
|
-
/* @__PURE__ */ (0,
|
|
3762
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.timer, children: [
|
|
3317
3763
|
minutes,
|
|
3318
3764
|
":",
|
|
3319
3765
|
seconds.toString().padStart(2, "0"),
|
|
3320
3766
|
" remaining"
|
|
3321
3767
|
] })
|
|
3322
3768
|
] }),
|
|
3323
|
-
/* @__PURE__ */ (0,
|
|
3324
|
-
/* @__PURE__ */ (0,
|
|
3325
|
-
/* @__PURE__ */ (0,
|
|
3326
|
-
/* @__PURE__ */ (0,
|
|
3769
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.steps, children: [
|
|
3770
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Step, { number: 1, text: "Open your phone's camera" }),
|
|
3771
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Step, { number: 2, text: "Point at the QR code" }),
|
|
3772
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Step, { number: 3, text: "Complete the capture on your phone" })
|
|
3327
3773
|
] }),
|
|
3328
|
-
/* @__PURE__ */ (0,
|
|
3329
|
-
/* @__PURE__ */ (0,
|
|
3774
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.divider, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: qrStyles.dividerText, children: "or" }) }),
|
|
3775
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { style: qrStyles.secondaryButton, onClick: onContinueOnDevice, children: "Continue on this device" })
|
|
3330
3776
|
] }) });
|
|
3331
3777
|
}
|
|
3332
3778
|
function Step({ number, text }) {
|
|
3333
|
-
return /* @__PURE__ */ (0,
|
|
3334
|
-
/* @__PURE__ */ (0,
|
|
3335
|
-
/* @__PURE__ */ (0,
|
|
3779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: qrStyles.step, children: [
|
|
3780
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: qrStyles.stepNumber, children: number }),
|
|
3781
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: qrStyles.stepText, children: text })
|
|
3336
3782
|
] });
|
|
3337
3783
|
}
|
|
3338
3784
|
var qrStyles = {
|