@koraidv/react 1.7.11 → 1.8.0
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 +819 -377
- package/dist/index.mjs +822 -380
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -47,7 +47,8 @@ function useKoraIDV() {
|
|
|
47
47
|
currentChallenge: null,
|
|
48
48
|
completedChallenges: 0,
|
|
49
49
|
isLoading: false,
|
|
50
|
-
error: null
|
|
50
|
+
error: null,
|
|
51
|
+
lastChallengeError: null
|
|
51
52
|
});
|
|
52
53
|
const [selectedDocumentType, setSelectedDocumentType] = useState(null);
|
|
53
54
|
const [documentFrontCaptured, setDocumentFrontCaptured] = useState(false);
|
|
@@ -246,14 +247,20 @@ function useKoraIDV() {
|
|
|
246
247
|
...prev,
|
|
247
248
|
completedChallenges: nextIndex,
|
|
248
249
|
currentChallenge: nextChallenge,
|
|
249
|
-
isLoading: false
|
|
250
|
+
isLoading: false,
|
|
251
|
+
// Clear any prior retake message — the user just succeeded.
|
|
252
|
+
lastChallengeError: null
|
|
250
253
|
}));
|
|
251
254
|
if (!nextChallenge) {
|
|
252
255
|
setState((prev) => ({ ...prev, step: "processing" }));
|
|
253
256
|
}
|
|
254
257
|
return true;
|
|
255
258
|
}
|
|
256
|
-
setState((prev) => ({
|
|
259
|
+
setState((prev) => ({
|
|
260
|
+
...prev,
|
|
261
|
+
isLoading: false,
|
|
262
|
+
lastChallengeError: retakeMessageForChallenge(currentChallenge.type)
|
|
263
|
+
}));
|
|
257
264
|
return false;
|
|
258
265
|
} catch (error) {
|
|
259
266
|
setState((prev) => ({
|
|
@@ -304,7 +311,8 @@ function useKoraIDV() {
|
|
|
304
311
|
currentChallenge: null,
|
|
305
312
|
completedChallenges: 0,
|
|
306
313
|
isLoading: false,
|
|
307
|
-
error: null
|
|
314
|
+
error: null,
|
|
315
|
+
lastChallengeError: null
|
|
308
316
|
});
|
|
309
317
|
}, [sdk]);
|
|
310
318
|
const retry = useCallback(() => {
|
|
@@ -331,9 +339,27 @@ function useKoraIDV() {
|
|
|
331
339
|
sdk
|
|
332
340
|
};
|
|
333
341
|
}
|
|
342
|
+
function retakeMessageForChallenge(type) {
|
|
343
|
+
switch (type) {
|
|
344
|
+
case "blink":
|
|
345
|
+
return "We didn't catch the blink \u2014 close both eyes briefly and try again.";
|
|
346
|
+
case "smile":
|
|
347
|
+
return "We didn't catch the smile \u2014 show your teeth and try again.";
|
|
348
|
+
case "turn_left":
|
|
349
|
+
return "Turn your head a bit further to the left and try again.";
|
|
350
|
+
case "turn_right":
|
|
351
|
+
return "Turn your head a bit further to the right and try again.";
|
|
352
|
+
case "nod_up":
|
|
353
|
+
return "Tilt your head a bit higher and try again.";
|
|
354
|
+
case "nod_down":
|
|
355
|
+
return "Tilt your head a bit lower and try again.";
|
|
356
|
+
default:
|
|
357
|
+
return "That attempt didn't pass \u2014 follow the prompt and try again.";
|
|
358
|
+
}
|
|
359
|
+
}
|
|
334
360
|
|
|
335
361
|
// src/components/VerificationFlow.tsx
|
|
336
|
-
import { useEffect as
|
|
362
|
+
import { useEffect as useEffect11, useState as useState9 } from "react";
|
|
337
363
|
import { KoraError as KoraError2, KoraErrorCode } from "@koraidv/core";
|
|
338
364
|
|
|
339
365
|
// src/components/styles.ts
|
|
@@ -400,6 +426,36 @@ function injectKeyframes() {
|
|
|
400
426
|
from { opacity: 0; transform: translateY(8px); }
|
|
401
427
|
to { opacity: 1; transform: translateY(0); }
|
|
402
428
|
}
|
|
429
|
+
/* \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 */
|
|
430
|
+
@keyframes kora-head-turn-right {
|
|
431
|
+
0%, 100% { transform: rotate(0deg); }
|
|
432
|
+
50% { transform: rotate(22deg); }
|
|
433
|
+
}
|
|
434
|
+
@keyframes kora-head-turn-left {
|
|
435
|
+
0%, 100% { transform: rotate(0deg); }
|
|
436
|
+
50% { transform: rotate(-22deg); }
|
|
437
|
+
}
|
|
438
|
+
@keyframes kora-head-tilt-up {
|
|
439
|
+
0%, 100% { transform: translateY(0); }
|
|
440
|
+
50% { transform: translateY(-6px) rotate(-6deg); }
|
|
441
|
+
}
|
|
442
|
+
@keyframes kora-head-tilt-down {
|
|
443
|
+
0%, 100% { transform: translateY(0); }
|
|
444
|
+
50% { transform: translateY(6px) rotate(6deg); }
|
|
445
|
+
}
|
|
446
|
+
@keyframes kora-smile {
|
|
447
|
+
0%, 100% { transform: scaleY(0.5); }
|
|
448
|
+
50% { transform: scaleY(1.2); }
|
|
449
|
+
}
|
|
450
|
+
@keyframes kora-blink {
|
|
451
|
+
0%, 80%, 100% { transform: scaleY(1); }
|
|
452
|
+
88% { transform: scaleY(0.05); }
|
|
453
|
+
}
|
|
454
|
+
@keyframes kora-nfc-wave {
|
|
455
|
+
0% { opacity: 0; transform: translateX(-4px); }
|
|
456
|
+
40% { opacity: 1; }
|
|
457
|
+
100% { opacity: 0; transform: translateX(6px); }
|
|
458
|
+
}
|
|
403
459
|
`;
|
|
404
460
|
document.head.appendChild(style);
|
|
405
461
|
}
|
|
@@ -1313,7 +1369,7 @@ var styles = {
|
|
|
1313
1369
|
};
|
|
1314
1370
|
|
|
1315
1371
|
// src/components/DesignSystem.tsx
|
|
1316
|
-
import { useEffect as useEffect2 } from "react";
|
|
1372
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1317
1373
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
1318
1374
|
function StepProgressBar({ total, current, isDark = false }) {
|
|
1319
1375
|
return /* @__PURE__ */ jsx2("div", { style: styles.progressBar, children: Array.from({ length: total }).map((_, i) => /* @__PURE__ */ jsx2(
|
|
@@ -1386,10 +1442,26 @@ function ScoreMetricRow({ label, score, icon, status, message }) {
|
|
|
1386
1442
|
}
|
|
1387
1443
|
);
|
|
1388
1444
|
}
|
|
1389
|
-
|
|
1445
|
+
var DEFAULT_AUTO_STEPS = [
|
|
1446
|
+
"Document analyzed",
|
|
1447
|
+
"Checking face match",
|
|
1448
|
+
"Finalizing results"
|
|
1449
|
+
];
|
|
1450
|
+
function ProcessingScreen({ steps, autoAdvance = true }) {
|
|
1390
1451
|
useEffect2(() => {
|
|
1391
1452
|
injectKeyframes();
|
|
1392
1453
|
}, []);
|
|
1454
|
+
const [autoIndex, setAutoIndex] = useState2(0);
|
|
1455
|
+
useEffect2(() => {
|
|
1456
|
+
if (steps || !autoAdvance) return;
|
|
1457
|
+
if (autoIndex >= DEFAULT_AUTO_STEPS.length - 1) return;
|
|
1458
|
+
const t = setTimeout(() => setAutoIndex((i) => i + 1), 1400);
|
|
1459
|
+
return () => clearTimeout(t);
|
|
1460
|
+
}, [autoIndex, steps, autoAdvance]);
|
|
1461
|
+
const renderedSteps = steps ? steps : DEFAULT_AUTO_STEPS.map((label, i) => ({
|
|
1462
|
+
label,
|
|
1463
|
+
status: i < autoIndex ? "done" : i === autoIndex ? "active" : "pending"
|
|
1464
|
+
}));
|
|
1393
1465
|
return /* @__PURE__ */ jsxs("div", { style: styles.processingContainer, children: [
|
|
1394
1466
|
/* @__PURE__ */ jsxs("div", { style: styles.spinnerContainer, children: [
|
|
1395
1467
|
/* @__PURE__ */ jsx2(
|
|
@@ -1440,7 +1512,7 @@ function ProcessingScreen({ steps }) {
|
|
|
1440
1512
|
}
|
|
1441
1513
|
)
|
|
1442
1514
|
] }),
|
|
1443
|
-
/* @__PURE__ */ jsx2("div", { style: styles.processingSteps, children:
|
|
1515
|
+
/* @__PURE__ */ jsx2("div", { style: styles.processingSteps, children: renderedSteps.map((step, i) => /* @__PURE__ */ jsxs("div", { style: styles.processingStep, children: [
|
|
1444
1516
|
/* @__PURE__ */ jsx2(
|
|
1445
1517
|
"div",
|
|
1446
1518
|
{
|
|
@@ -1608,11 +1680,11 @@ function ConsentItem({
|
|
|
1608
1680
|
}
|
|
1609
1681
|
|
|
1610
1682
|
// src/components/CountrySelectionScreen.tsx
|
|
1611
|
-
import { useState as
|
|
1683
|
+
import { useState as useState3, useMemo as useMemo2 } from "react";
|
|
1612
1684
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1613
1685
|
function CountrySelectionScreen({ countries, onSelect, onCancel }) {
|
|
1614
|
-
const [selected, setSelected] =
|
|
1615
|
-
const [searchQuery, setSearchQuery] =
|
|
1686
|
+
const [selected, setSelected] = useState3(null);
|
|
1687
|
+
const [searchQuery, setSearchQuery] = useState3("");
|
|
1616
1688
|
const filteredCountries = useMemo2(() => {
|
|
1617
1689
|
const countryList = countries || [];
|
|
1618
1690
|
if (!searchQuery.trim()) return countryList;
|
|
@@ -1762,8 +1834,243 @@ function getIcon(type) {
|
|
|
1762
1834
|
}
|
|
1763
1835
|
|
|
1764
1836
|
// src/components/DocumentCaptureScreen.tsx
|
|
1765
|
-
import { useRef as
|
|
1766
|
-
|
|
1837
|
+
import { useRef as useRef3, useEffect as useEffect5, useState as useState5, useCallback as useCallback2 } from "react";
|
|
1838
|
+
|
|
1839
|
+
// src/components/VisualGuides.tsx
|
|
1840
|
+
import { useEffect as useEffect3 } from "react";
|
|
1841
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1842
|
+
function visualGuideForChallenge(challengeType) {
|
|
1843
|
+
switch (challengeType) {
|
|
1844
|
+
case "turn_left":
|
|
1845
|
+
return "livenessTurnLeft";
|
|
1846
|
+
case "turn_right":
|
|
1847
|
+
return "livenessTurnRight";
|
|
1848
|
+
case "nod_up":
|
|
1849
|
+
return "livenessLookUp";
|
|
1850
|
+
case "nod_down":
|
|
1851
|
+
return "livenessLookDown";
|
|
1852
|
+
case "smile":
|
|
1853
|
+
return "livenessSmile";
|
|
1854
|
+
case "blink":
|
|
1855
|
+
return "livenessBlink";
|
|
1856
|
+
default:
|
|
1857
|
+
return null;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
function VisualGuide({ kind, size = 96 }) {
|
|
1861
|
+
useEffect3(() => {
|
|
1862
|
+
injectKeyframes();
|
|
1863
|
+
}, []);
|
|
1864
|
+
const common = { width: size, height: size, viewBox: "0 0 100 100" };
|
|
1865
|
+
const fg = colors.teal;
|
|
1866
|
+
const dim = "rgba(255,255,255,0.3)";
|
|
1867
|
+
switch (kind) {
|
|
1868
|
+
case "docFront":
|
|
1869
|
+
return /* @__PURE__ */ jsx6(DocFront, { ...common, fg, dim });
|
|
1870
|
+
case "docBack":
|
|
1871
|
+
return /* @__PURE__ */ jsx6(DocBack, { ...common, fg, dim });
|
|
1872
|
+
case "selfie":
|
|
1873
|
+
return /* @__PURE__ */ jsx6(Selfie, { ...common, fg, dim });
|
|
1874
|
+
case "nfcScan":
|
|
1875
|
+
return /* @__PURE__ */ jsx6(NfcScan, { ...common, fg, dim });
|
|
1876
|
+
case "livenessTurnLeft":
|
|
1877
|
+
return /* @__PURE__ */ jsx6(HeadTurn, { ...common, fg, dim, right: false });
|
|
1878
|
+
case "livenessTurnRight":
|
|
1879
|
+
return /* @__PURE__ */ jsx6(HeadTurn, { ...common, fg, dim, right: true });
|
|
1880
|
+
case "livenessLookUp":
|
|
1881
|
+
return /* @__PURE__ */ jsx6(HeadTilt, { ...common, fg, dim, up: true });
|
|
1882
|
+
case "livenessLookDown":
|
|
1883
|
+
return /* @__PURE__ */ jsx6(HeadTilt, { ...common, fg, dim, up: false });
|
|
1884
|
+
case "livenessSmile":
|
|
1885
|
+
return /* @__PURE__ */ jsx6(Smile, { ...common, fg, dim });
|
|
1886
|
+
case "livenessBlink":
|
|
1887
|
+
return /* @__PURE__ */ jsx6(Blink, { ...common, fg, dim });
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
function DocFront({ width, height, viewBox, fg, dim }) {
|
|
1891
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1892
|
+
/* @__PURE__ */ jsx6("rect", { x: "8", y: "26", width: "84", height: "48", rx: "5", stroke: fg, strokeWidth: "2.5" }),
|
|
1893
|
+
/* @__PURE__ */ jsx6("rect", { x: "14", y: "34", width: "22", height: "28", rx: "2", fill: dim }),
|
|
1894
|
+
/* @__PURE__ */ jsx6("rect", { x: "42", y: "36", width: "44", height: "3", rx: "1.5", fill: fg }),
|
|
1895
|
+
/* @__PURE__ */ jsx6("rect", { x: "42", y: "44", width: "36", height: "2.5", rx: "1.25", fill: dim }),
|
|
1896
|
+
/* @__PURE__ */ jsx6("rect", { x: "42", y: "50", width: "40", height: "2.5", rx: "1.25", fill: dim }),
|
|
1897
|
+
/* @__PURE__ */ jsx6("rect", { x: "42", y: "56", width: "30", height: "2.5", rx: "1.25", fill: dim })
|
|
1898
|
+
] });
|
|
1899
|
+
}
|
|
1900
|
+
function DocBack({ width, height, viewBox, fg, dim }) {
|
|
1901
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1902
|
+
/* @__PURE__ */ jsx6("rect", { x: "8", y: "26", width: "84", height: "48", rx: "5", stroke: fg, strokeWidth: "2.5" }),
|
|
1903
|
+
[16, 19, 22, 26, 28, 32, 35, 39, 42, 46, 49, 53, 56, 60].map((x, i) => /* @__PURE__ */ jsx6(
|
|
1904
|
+
"rect",
|
|
1905
|
+
{
|
|
1906
|
+
x,
|
|
1907
|
+
y: "34",
|
|
1908
|
+
width: i % 3 === 0 ? 2 : 1.2,
|
|
1909
|
+
height: "20",
|
|
1910
|
+
fill: fg
|
|
1911
|
+
},
|
|
1912
|
+
i
|
|
1913
|
+
)),
|
|
1914
|
+
/* @__PURE__ */ jsx6("line", { x1: "14", y1: "64", x2: "58", y2: "64", stroke: dim, strokeWidth: "1.5" }),
|
|
1915
|
+
/* @__PURE__ */ jsx6("rect", { x: "66", y: "34", width: "20", height: "20", rx: "1", fill: dim })
|
|
1916
|
+
] });
|
|
1917
|
+
}
|
|
1918
|
+
function Selfie({ width, height, viewBox, fg, dim }) {
|
|
1919
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1920
|
+
/* @__PURE__ */ jsx6("ellipse", { cx: "50", cy: "42", rx: "22", ry: "28", stroke: fg, strokeWidth: "2.5" }),
|
|
1921
|
+
/* @__PURE__ */ jsx6("circle", { cx: "42", cy: "38", r: "2.5", fill: fg }),
|
|
1922
|
+
/* @__PURE__ */ jsx6("circle", { cx: "58", cy: "38", r: "2.5", fill: fg }),
|
|
1923
|
+
/* @__PURE__ */ jsx6("path", { d: "M 40 50 Q 50 56 60 50", stroke: fg, strokeWidth: "2", strokeLinecap: "round", fill: "none" }),
|
|
1924
|
+
/* @__PURE__ */ jsx6("path", { d: "M 18 92 Q 18 76 36 70 L 64 70 Q 82 76 82 92", stroke: dim, strokeWidth: "2", fill: "none" })
|
|
1925
|
+
] });
|
|
1926
|
+
}
|
|
1927
|
+
function NfcScan({ width, height, viewBox, fg, dim }) {
|
|
1928
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1929
|
+
/* @__PURE__ */ jsx6("rect", { x: "14", y: "40", width: "40", height: "50", rx: "3", stroke: dim, strokeWidth: "2" }),
|
|
1930
|
+
/* @__PURE__ */ jsx6("circle", { cx: "34", cy: "60", r: "6", stroke: dim, strokeWidth: "1.5" }),
|
|
1931
|
+
/* @__PURE__ */ jsx6("rect", { x: "62", y: "22", width: "26", height: "52", rx: "4", stroke: fg, strokeWidth: "2.5" }),
|
|
1932
|
+
/* @__PURE__ */ jsx6("rect", { x: "66", y: "26", width: "18", height: "38", rx: "1.5", fill: dim, opacity: "0.5" }),
|
|
1933
|
+
/* @__PURE__ */ jsx6("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" } }),
|
|
1934
|
+
/* @__PURE__ */ jsx6("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" } })
|
|
1935
|
+
] });
|
|
1936
|
+
}
|
|
1937
|
+
function HeadTurn({ width, height, viewBox, fg, dim, right }) {
|
|
1938
|
+
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";
|
|
1939
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1940
|
+
/* @__PURE__ */ jsx6("path", { d: arrowPath, stroke: fg, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
|
|
1941
|
+
/* @__PURE__ */ jsxs5(
|
|
1942
|
+
"g",
|
|
1943
|
+
{
|
|
1944
|
+
style: {
|
|
1945
|
+
transformOrigin: "50px 56px",
|
|
1946
|
+
animation: right ? "kora-head-turn-right 2s ease-in-out infinite" : "kora-head-turn-left 2s ease-in-out infinite"
|
|
1947
|
+
},
|
|
1948
|
+
children: [
|
|
1949
|
+
/* @__PURE__ */ jsx6("ellipse", { cx: "50", cy: "55", rx: "20", ry: "26", stroke: fg, strokeWidth: "2.5" }),
|
|
1950
|
+
/* @__PURE__ */ jsx6("circle", { cx: "42", cy: "50", r: "2", fill: fg }),
|
|
1951
|
+
/* @__PURE__ */ jsx6("circle", { cx: "58", cy: "50", r: "2", fill: fg }),
|
|
1952
|
+
/* @__PURE__ */ jsx6("path", { d: "M 50 54 L 50 62", stroke: dim, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
1953
|
+
]
|
|
1954
|
+
}
|
|
1955
|
+
)
|
|
1956
|
+
] });
|
|
1957
|
+
}
|
|
1958
|
+
function HeadTilt({ width, height, viewBox, fg, dim, up }) {
|
|
1959
|
+
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";
|
|
1960
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1961
|
+
/* @__PURE__ */ jsx6("path", { d: arrowPath, stroke: fg, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", opacity: "0.4", fill: "none" }),
|
|
1962
|
+
/* @__PURE__ */ jsxs5(
|
|
1963
|
+
"g",
|
|
1964
|
+
{
|
|
1965
|
+
style: {
|
|
1966
|
+
transformOrigin: "50px 56px",
|
|
1967
|
+
animation: up ? "kora-head-tilt-up 2s ease-in-out infinite" : "kora-head-tilt-down 2s ease-in-out infinite"
|
|
1968
|
+
},
|
|
1969
|
+
children: [
|
|
1970
|
+
/* @__PURE__ */ jsx6("ellipse", { cx: "50", cy: "55", rx: "20", ry: "26", stroke: fg, strokeWidth: "2.5" }),
|
|
1971
|
+
/* @__PURE__ */ jsx6("circle", { cx: "42", cy: "50", r: "2", fill: fg }),
|
|
1972
|
+
/* @__PURE__ */ jsx6("circle", { cx: "58", cy: "50", r: "2", fill: fg }),
|
|
1973
|
+
/* @__PURE__ */ jsx6("path", { d: "M 50 54 L 50 62", stroke: dim, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
1974
|
+
]
|
|
1975
|
+
}
|
|
1976
|
+
)
|
|
1977
|
+
] });
|
|
1978
|
+
}
|
|
1979
|
+
function Smile({ width, height, viewBox, fg, dim }) {
|
|
1980
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
1981
|
+
/* @__PURE__ */ jsx6("ellipse", { cx: "50", cy: "50", rx: "24", ry: "30", stroke: fg, strokeWidth: "2.5" }),
|
|
1982
|
+
/* @__PURE__ */ jsx6("circle", { cx: "40", cy: "44", r: "2.5", fill: fg }),
|
|
1983
|
+
/* @__PURE__ */ jsx6("circle", { cx: "60", cy: "44", r: "2.5", fill: fg }),
|
|
1984
|
+
/* @__PURE__ */ jsx6(
|
|
1985
|
+
"path",
|
|
1986
|
+
{
|
|
1987
|
+
d: "M 38 60 Q 50 68 62 60",
|
|
1988
|
+
stroke: fg,
|
|
1989
|
+
strokeWidth: "2.5",
|
|
1990
|
+
strokeLinecap: "round",
|
|
1991
|
+
fill: "none",
|
|
1992
|
+
style: { animation: "kora-smile 2s ease-in-out infinite", transformOrigin: "50px 60px" }
|
|
1993
|
+
}
|
|
1994
|
+
),
|
|
1995
|
+
/* @__PURE__ */ jsx6("line", { x1: "40", y1: "60", x2: "60", y2: "60", stroke: dim, strokeWidth: "1.5", opacity: "0.3" })
|
|
1996
|
+
] });
|
|
1997
|
+
}
|
|
1998
|
+
function Blink({ width, height, viewBox, fg, dim }) {
|
|
1999
|
+
return /* @__PURE__ */ jsxs5("svg", { width, height, viewBox, fill: "none", children: [
|
|
2000
|
+
/* @__PURE__ */ jsx6("ellipse", { cx: "50", cy: "50", rx: "24", ry: "30", stroke: fg, strokeWidth: "2.5" }),
|
|
2001
|
+
/* @__PURE__ */ jsxs5("g", { style: { animation: "kora-blink 1.6s ease-in-out infinite" }, children: [
|
|
2002
|
+
/* @__PURE__ */ jsx6("circle", { cx: "40", cy: "44", r: "3", fill: fg }),
|
|
2003
|
+
/* @__PURE__ */ jsx6("circle", { cx: "60", cy: "44", r: "3", fill: fg })
|
|
2004
|
+
] }),
|
|
2005
|
+
/* @__PURE__ */ jsx6("path", { d: "M 42 60 Q 50 64 58 60", stroke: dim, strokeWidth: "2", strokeLinecap: "round", fill: "none" })
|
|
2006
|
+
] });
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// src/hooks/useDocumentDetection.ts
|
|
2010
|
+
import { useEffect as useEffect4, useRef as useRef2, useState as useState4 } from "react";
|
|
2011
|
+
var FRAME_INTERVAL_MS = 300;
|
|
2012
|
+
function useDocumentDetection(videoRef, side) {
|
|
2013
|
+
const [signals, setSignals] = useState4({
|
|
2014
|
+
documentDetected: false,
|
|
2015
|
+
detectorActive: false
|
|
2016
|
+
});
|
|
2017
|
+
const detectorRef = useRef2(null);
|
|
2018
|
+
const intervalRef = useRef2(null);
|
|
2019
|
+
useEffect4(() => {
|
|
2020
|
+
let cancelled = false;
|
|
2021
|
+
async function setup() {
|
|
2022
|
+
const win = typeof window !== "undefined" ? window : null;
|
|
2023
|
+
if (!win) return;
|
|
2024
|
+
let DetectorCtor = null;
|
|
2025
|
+
if (side === "front" && "FaceDetector" in win) {
|
|
2026
|
+
DetectorCtor = win["FaceDetector"];
|
|
2027
|
+
} else if (side === "back" && "BarcodeDetector" in win) {
|
|
2028
|
+
DetectorCtor = win["BarcodeDetector"];
|
|
2029
|
+
}
|
|
2030
|
+
if (!DetectorCtor) {
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
try {
|
|
2034
|
+
const detector = new DetectorCtor(
|
|
2035
|
+
side === "front" ? { fastMode: true, maxDetectedFaces: 1 } : { formats: ["pdf417", "qr_code", "data_matrix", "code_128"] }
|
|
2036
|
+
);
|
|
2037
|
+
if (cancelled) return;
|
|
2038
|
+
detectorRef.current = detector;
|
|
2039
|
+
setSignals((prev) => ({ ...prev, detectorActive: true }));
|
|
2040
|
+
} catch {
|
|
2041
|
+
return;
|
|
2042
|
+
}
|
|
2043
|
+
intervalRef.current = setInterval(async () => {
|
|
2044
|
+
const detector = detectorRef.current;
|
|
2045
|
+
const video = videoRef.current;
|
|
2046
|
+
if (!detector || !video || video.readyState < 2) return;
|
|
2047
|
+
try {
|
|
2048
|
+
const results = await detector.detect(video);
|
|
2049
|
+
if (cancelled) return;
|
|
2050
|
+
setSignals((prev) => {
|
|
2051
|
+
const next = results.length > 0;
|
|
2052
|
+
if (prev.documentDetected === next) return prev;
|
|
2053
|
+
return { ...prev, documentDetected: next };
|
|
2054
|
+
});
|
|
2055
|
+
} catch {
|
|
2056
|
+
}
|
|
2057
|
+
}, FRAME_INTERVAL_MS);
|
|
2058
|
+
}
|
|
2059
|
+
setup();
|
|
2060
|
+
return () => {
|
|
2061
|
+
cancelled = true;
|
|
2062
|
+
if (intervalRef.current) {
|
|
2063
|
+
clearInterval(intervalRef.current);
|
|
2064
|
+
intervalRef.current = null;
|
|
2065
|
+
}
|
|
2066
|
+
detectorRef.current = null;
|
|
2067
|
+
};
|
|
2068
|
+
}, [videoRef, side]);
|
|
2069
|
+
return signals;
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
// src/components/DocumentCaptureScreen.tsx
|
|
2073
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1767
2074
|
var qualityIssueMessages = {
|
|
1768
2075
|
face_blurred: "Photo on document is blurry. Retake in better lighting.",
|
|
1769
2076
|
low_resolution: "Image quality too low. Move closer to document.",
|
|
@@ -1780,23 +2087,25 @@ function DocumentCaptureScreen({
|
|
|
1780
2087
|
requiresBack = true,
|
|
1781
2088
|
onQualityCheck,
|
|
1782
2089
|
onCapture,
|
|
1783
|
-
onCancel
|
|
2090
|
+
onCancel,
|
|
2091
|
+
showVisualGuides = true
|
|
1784
2092
|
}) {
|
|
1785
|
-
const videoRef =
|
|
1786
|
-
const canvasRef =
|
|
1787
|
-
const guideRef =
|
|
1788
|
-
const [stream, setStream] =
|
|
1789
|
-
const
|
|
1790
|
-
const [
|
|
1791
|
-
const [
|
|
1792
|
-
const [
|
|
1793
|
-
const [
|
|
1794
|
-
const [
|
|
1795
|
-
const [
|
|
1796
|
-
|
|
2093
|
+
const videoRef = useRef3(null);
|
|
2094
|
+
const canvasRef = useRef3(null);
|
|
2095
|
+
const guideRef = useRef3(null);
|
|
2096
|
+
const [stream, setStream] = useState5(null);
|
|
2097
|
+
const documentSignals = useDocumentDetection(videoRef, side);
|
|
2098
|
+
const [isCapturing, setIsCapturing] = useState5(false);
|
|
2099
|
+
const [error, setError] = useState5(null);
|
|
2100
|
+
const [capturedImage, setCapturedImage] = useState5(null);
|
|
2101
|
+
const [capturedBlob, setCapturedBlob] = useState5(null);
|
|
2102
|
+
const [qualityResult, setQualityResult] = useState5(null);
|
|
2103
|
+
const [isCheckingQuality, setIsCheckingQuality] = useState5(false);
|
|
2104
|
+
const [retakeCount, setRetakeCount] = useState5(0);
|
|
2105
|
+
useEffect5(() => {
|
|
1797
2106
|
injectKeyframes();
|
|
1798
2107
|
}, []);
|
|
1799
|
-
|
|
2108
|
+
useEffect5(() => {
|
|
1800
2109
|
let mounted = true;
|
|
1801
2110
|
async function startCamera() {
|
|
1802
2111
|
try {
|
|
@@ -1818,7 +2127,7 @@ function DocumentCaptureScreen({
|
|
|
1818
2127
|
mounted = false;
|
|
1819
2128
|
};
|
|
1820
2129
|
}, [capturedImage]);
|
|
1821
|
-
|
|
2130
|
+
useEffect5(() => {
|
|
1822
2131
|
return () => {
|
|
1823
2132
|
stream?.getTracks().forEach((t) => t.stop());
|
|
1824
2133
|
};
|
|
@@ -1911,24 +2220,24 @@ function DocumentCaptureScreen({
|
|
|
1911
2220
|
}
|
|
1912
2221
|
};
|
|
1913
2222
|
if (error) {
|
|
1914
|
-
return /* @__PURE__ */
|
|
1915
|
-
/* @__PURE__ */
|
|
1916
|
-
/* @__PURE__ */
|
|
2223
|
+
return /* @__PURE__ */ jsx7("div", { style: styles.container, children: /* @__PURE__ */ jsxs6("div", { style: styles.errorContainer, children: [
|
|
2224
|
+
/* @__PURE__ */ jsx7("p", { style: styles.errorText, children: error }),
|
|
2225
|
+
/* @__PURE__ */ jsx7("button", { style: styles.primaryButton, onClick: onCancel, children: "Go Back" })
|
|
1917
2226
|
] }) });
|
|
1918
2227
|
}
|
|
1919
2228
|
if (capturedImage) {
|
|
1920
2229
|
const qualityPassed = qualityResult && qualityResult.qualityScore >= 60;
|
|
1921
2230
|
const qualityFailed = qualityResult && qualityResult.qualityScore < 60;
|
|
1922
2231
|
const canContinueAnyway = qualityFailed && retakeCount >= 2;
|
|
1923
|
-
return /* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
1927
|
-
/* @__PURE__ */
|
|
1928
|
-
/* @__PURE__ */
|
|
2232
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.darkContainer, children: [
|
|
2233
|
+
/* @__PURE__ */ jsx7(StepProgressBar, { total: 5, current: 3, isDark: true }),
|
|
2234
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.darkScreenHeader, children: [
|
|
2235
|
+
/* @__PURE__ */ jsx7("div", { style: { width: 40 } }),
|
|
2236
|
+
/* @__PURE__ */ jsx7("h1", { style: styles.darkScreenTitle, children: "Review your photo" }),
|
|
2237
|
+
/* @__PURE__ */ jsx7("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
1929
2238
|
] }),
|
|
1930
|
-
/* @__PURE__ */
|
|
1931
|
-
/* @__PURE__ */
|
|
2239
|
+
/* @__PURE__ */ jsx7("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "24px" }, children: /* @__PURE__ */ jsxs6("div", { style: styles.reviewCard, children: [
|
|
2240
|
+
/* @__PURE__ */ jsx7(
|
|
1932
2241
|
"img",
|
|
1933
2242
|
{
|
|
1934
2243
|
src: capturedImage,
|
|
@@ -1936,42 +2245,42 @@ function DocumentCaptureScreen({
|
|
|
1936
2245
|
style: { width: "100%", maxWidth: "300px", borderRadius: "16px", display: "block", margin: "0 auto" }
|
|
1937
2246
|
}
|
|
1938
2247
|
),
|
|
1939
|
-
isCheckingQuality && /* @__PURE__ */
|
|
1940
|
-
qualityPassed && /* @__PURE__ */
|
|
1941
|
-
/* @__PURE__ */
|
|
2248
|
+
isCheckingQuality && /* @__PURE__ */ jsx7("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ jsx7("span", { style: { ...styles.reviewBadge, backgroundColor: "rgba(255,255,255,0.1)" }, children: "Checking quality..." }) }),
|
|
2249
|
+
qualityPassed && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
2250
|
+
/* @__PURE__ */ jsx7("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ jsxs6("span", { style: styles.reviewBadge, children: [
|
|
1942
2251
|
"\u2713 Quality score: ",
|
|
1943
2252
|
Math.round(qualityResult.qualityScore),
|
|
1944
2253
|
"%"
|
|
1945
2254
|
] }) }),
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
1948
|
-
/* @__PURE__ */
|
|
1949
|
-
/* @__PURE__ */
|
|
2255
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.qualityChecks, children: [
|
|
2256
|
+
/* @__PURE__ */ jsx7(QualityCheck, { label: "Sharp" }),
|
|
2257
|
+
/* @__PURE__ */ jsx7(QualityCheck, { label: "Well-lit" }),
|
|
2258
|
+
/* @__PURE__ */ jsx7(QualityCheck, { label: "Readable" })
|
|
1950
2259
|
] })
|
|
1951
2260
|
] }),
|
|
1952
|
-
qualityFailed && /* @__PURE__ */
|
|
1953
|
-
/* @__PURE__ */
|
|
2261
|
+
qualityFailed && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
2262
|
+
/* @__PURE__ */ jsx7("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ jsxs6("span", { style: { ...styles.reviewBadge, backgroundColor: "rgba(239,68,68,0.15)", color: "#ef4444" }, children: [
|
|
1954
2263
|
"\u26A0 Quality score: ",
|
|
1955
2264
|
Math.round(qualityResult.qualityScore),
|
|
1956
2265
|
"%"
|
|
1957
2266
|
] }) }),
|
|
1958
|
-
/* @__PURE__ */
|
|
2267
|
+
/* @__PURE__ */ jsx7("div", { style: { padding: "12px 0" }, children: qualityResult.qualityIssues.map((issue, i) => /* @__PURE__ */ jsx7("p", { style: { color: "rgba(255,255,255,0.7)", fontSize: "13px", margin: "4px 0", textAlign: "center" }, children: qualityIssueMessages[issue] || issue }, i)) })
|
|
1959
2268
|
] }),
|
|
1960
|
-
!qualityResult && !isCheckingQuality && /* @__PURE__ */
|
|
1961
|
-
/* @__PURE__ */
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
/* @__PURE__ */
|
|
1964
|
-
/* @__PURE__ */
|
|
1965
|
-
/* @__PURE__ */
|
|
2269
|
+
!qualityResult && !isCheckingQuality && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
2270
|
+
/* @__PURE__ */ jsx7("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ jsx7("span", { style: styles.reviewBadge, children: "\u2713 Good quality" }) }),
|
|
2271
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.qualityChecks, children: [
|
|
2272
|
+
/* @__PURE__ */ jsx7(QualityCheck, { label: "Sharp" }),
|
|
2273
|
+
/* @__PURE__ */ jsx7(QualityCheck, { label: "Well-lit" }),
|
|
2274
|
+
/* @__PURE__ */ jsx7(QualityCheck, { label: "No glare" })
|
|
1966
2275
|
] })
|
|
1967
2276
|
] })
|
|
1968
2277
|
] }) }),
|
|
1969
|
-
/* @__PURE__ */
|
|
1970
|
-
/* @__PURE__ */
|
|
1971
|
-
canContinueAnyway && /* @__PURE__ */
|
|
1972
|
-
] }) : /* @__PURE__ */
|
|
1973
|
-
/* @__PURE__ */
|
|
1974
|
-
/* @__PURE__ */
|
|
2278
|
+
/* @__PURE__ */ jsx7("div", { style: styles.reviewButtonsRow, children: qualityFailed ? /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
2279
|
+
/* @__PURE__ */ jsx7("button", { style: { ...styles.darkOutlineButton, flex: 1 }, onClick: handleRetake, children: "Retake" }),
|
|
2280
|
+
canContinueAnyway && /* @__PURE__ */ jsx7("button", { style: { ...styles.primaryButton, flex: 1 }, onClick: handleContinueAnyway, children: "Continue anyway" })
|
|
2281
|
+
] }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
2282
|
+
/* @__PURE__ */ jsx7("button", { style: { ...styles.darkOutlineButton, flex: 1 }, onClick: handleRetake, children: "Retake" }),
|
|
2283
|
+
/* @__PURE__ */ jsx7(
|
|
1975
2284
|
"button",
|
|
1976
2285
|
{
|
|
1977
2286
|
style: { ...styles.primaryButton, flex: 1, opacity: isCheckingQuality ? 0.5 : 1 },
|
|
@@ -1983,29 +2292,54 @@ function DocumentCaptureScreen({
|
|
|
1983
2292
|
] }) })
|
|
1984
2293
|
] });
|
|
1985
2294
|
}
|
|
1986
|
-
return /* @__PURE__ */
|
|
1987
|
-
/* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
1989
|
-
/* @__PURE__ */
|
|
1990
|
-
/* @__PURE__ */
|
|
1991
|
-
/* @__PURE__ */
|
|
1992
|
-
documentType && /* @__PURE__ */
|
|
2295
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.captureContainer, children: [
|
|
2296
|
+
/* @__PURE__ */ jsx7(StepProgressBar, { total: 5, current: 3, isDark: true }),
|
|
2297
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.darkScreenHeader, children: [
|
|
2298
|
+
/* @__PURE__ */ jsx7("div", { style: { width: 40 } }),
|
|
2299
|
+
/* @__PURE__ */ jsxs6("div", { style: { flex: 1, textAlign: "center" }, children: [
|
|
2300
|
+
/* @__PURE__ */ jsx7("h1", { style: { ...styles.darkScreenTitle, margin: 0 }, children: side === "front" ? "Front of ID" : "Back of ID" }),
|
|
2301
|
+
documentType && /* @__PURE__ */ jsx7("p", { style: styles.darkScreenSubtitle, children: documentType })
|
|
1993
2302
|
] }),
|
|
1994
|
-
/* @__PURE__ */
|
|
2303
|
+
/* @__PURE__ */ jsx7("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
1995
2304
|
] }),
|
|
1996
|
-
/* @__PURE__ */
|
|
1997
|
-
|
|
1998
|
-
/* @__PURE__ */
|
|
1999
|
-
|
|
2000
|
-
/* @__PURE__ */
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2305
|
+
showVisualGuides && /* @__PURE__ */ jsx7("div", { style: { display: "flex", justifyContent: "center", padding: "6px 0 0" }, children: /* @__PURE__ */ jsx7(VisualGuide, { kind: side === "front" ? "docFront" : "docBack", size: 56 }) }),
|
|
2306
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.cameraContainer, children: [
|
|
2307
|
+
/* @__PURE__ */ jsx7("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true, style: styles.cameraVideo }),
|
|
2308
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.documentOverlay, children: [
|
|
2309
|
+
/* @__PURE__ */ jsxs6("div", { ref: guideRef, style: styles.documentFrame, children: [
|
|
2310
|
+
/* @__PURE__ */ jsx7("div", { style: { ...styles.corner, top: 0, left: 0 } }),
|
|
2311
|
+
/* @__PURE__ */ jsx7("div", { style: { ...styles.corner, top: 0, right: 0, transform: "rotate(90deg)" } }),
|
|
2312
|
+
/* @__PURE__ */ jsx7("div", { style: { ...styles.corner, bottom: 0, right: 0, transform: "rotate(180deg)" } }),
|
|
2313
|
+
/* @__PURE__ */ jsx7("div", { style: { ...styles.corner, bottom: 0, left: 0, transform: "rotate(270deg)" } }),
|
|
2314
|
+
/* @__PURE__ */ jsx7("div", { style: styles.scanLine })
|
|
2315
|
+
] }),
|
|
2316
|
+
documentSignals.detectorActive && /* @__PURE__ */ jsx7(
|
|
2317
|
+
"div",
|
|
2318
|
+
{
|
|
2319
|
+
style: {
|
|
2320
|
+
position: "absolute",
|
|
2321
|
+
bottom: "24px",
|
|
2322
|
+
left: "50%",
|
|
2323
|
+
transform: "translateX(-50%)",
|
|
2324
|
+
padding: "6px 14px",
|
|
2325
|
+
borderRadius: "999px",
|
|
2326
|
+
fontSize: "12px",
|
|
2327
|
+
fontWeight: 600,
|
|
2328
|
+
color: documentSignals.documentDetected ? colors.success : "rgba(255,255,255,0.55)",
|
|
2329
|
+
backgroundColor: documentSignals.documentDetected ? "rgba(16,185,129,0.15)" : "rgba(0,0,0,0.35)",
|
|
2330
|
+
border: documentSignals.documentDetected ? "1px solid rgba(16,185,129,0.4)" : "1px solid rgba(255,255,255,0.12)",
|
|
2331
|
+
transition: "all 200ms",
|
|
2332
|
+
pointerEvents: "none",
|
|
2333
|
+
whiteSpace: "nowrap"
|
|
2334
|
+
},
|
|
2335
|
+
children: documentSignals.documentDetected ? "\u2713 Document detected \u2014 fill the frame" : "Position your ID inside the guide"
|
|
2336
|
+
}
|
|
2337
|
+
)
|
|
2338
|
+
] }),
|
|
2339
|
+
/* @__PURE__ */ jsx7("canvas", { ref: canvasRef, style: { display: "none" } })
|
|
2006
2340
|
] }),
|
|
2007
|
-
/* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2341
|
+
/* @__PURE__ */ jsxs6("div", { style: styles.stepPillsRow, children: [
|
|
2342
|
+
/* @__PURE__ */ jsx7(
|
|
2009
2343
|
"span",
|
|
2010
2344
|
{
|
|
2011
2345
|
style: {
|
|
@@ -2016,7 +2350,7 @@ function DocumentCaptureScreen({
|
|
|
2016
2350
|
children: "Front"
|
|
2017
2351
|
}
|
|
2018
2352
|
),
|
|
2019
|
-
requiresBack && /* @__PURE__ */
|
|
2353
|
+
requiresBack && /* @__PURE__ */ jsx7(
|
|
2020
2354
|
"span",
|
|
2021
2355
|
{
|
|
2022
2356
|
style: {
|
|
@@ -2028,7 +2362,7 @@ function DocumentCaptureScreen({
|
|
|
2028
2362
|
}
|
|
2029
2363
|
)
|
|
2030
2364
|
] }),
|
|
2031
|
-
/* @__PURE__ */
|
|
2365
|
+
/* @__PURE__ */ jsx7("div", { style: { textAlign: "center", padding: "8px 0" }, children: /* @__PURE__ */ jsxs6(
|
|
2032
2366
|
"span",
|
|
2033
2367
|
{
|
|
2034
2368
|
style: {
|
|
@@ -2037,44 +2371,44 @@ function DocumentCaptureScreen({
|
|
|
2037
2371
|
color: colors.teal
|
|
2038
2372
|
},
|
|
2039
2373
|
children: [
|
|
2040
|
-
/* @__PURE__ */
|
|
2374
|
+
/* @__PURE__ */ jsx7("span", { style: { ...styles.pulsingDot, backgroundColor: colors.teal } }),
|
|
2041
2375
|
"Scanning document..."
|
|
2042
2376
|
]
|
|
2043
2377
|
}
|
|
2044
2378
|
) }),
|
|
2045
|
-
/* @__PURE__ */
|
|
2379
|
+
/* @__PURE__ */ jsx7("div", { style: styles.captureFooter, children: /* @__PURE__ */ jsx7(
|
|
2046
2380
|
"button",
|
|
2047
2381
|
{
|
|
2048
2382
|
style: { ...styles.captureButton, opacity: isCapturing ? 0.5 : 1 },
|
|
2049
2383
|
onClick: handleCapture,
|
|
2050
2384
|
disabled: isCapturing,
|
|
2051
|
-
children: /* @__PURE__ */
|
|
2385
|
+
children: /* @__PURE__ */ jsx7("div", { style: styles.captureButtonInner })
|
|
2052
2386
|
}
|
|
2053
2387
|
) })
|
|
2054
2388
|
] });
|
|
2055
2389
|
}
|
|
2056
2390
|
function QualityCheck({ label }) {
|
|
2057
|
-
return /* @__PURE__ */
|
|
2058
|
-
/* @__PURE__ */
|
|
2059
|
-
/* @__PURE__ */
|
|
2391
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.qualityCheck, children: [
|
|
2392
|
+
/* @__PURE__ */ jsx7("div", { style: styles.qualityCheckIcon, children: "\u2713" }),
|
|
2393
|
+
/* @__PURE__ */ jsx7("span", { style: styles.qualityCheckLabel, children: label })
|
|
2060
2394
|
] });
|
|
2061
2395
|
}
|
|
2062
2396
|
|
|
2063
2397
|
// src/components/FlipDocumentScreen.tsx
|
|
2064
|
-
import { useEffect as
|
|
2065
|
-
import { jsx as
|
|
2398
|
+
import { useEffect as useEffect6 } from "react";
|
|
2399
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2066
2400
|
function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
2067
|
-
|
|
2401
|
+
useEffect6(() => {
|
|
2068
2402
|
injectKeyframes();
|
|
2069
2403
|
}, []);
|
|
2070
|
-
return /* @__PURE__ */
|
|
2071
|
-
/* @__PURE__ */
|
|
2072
|
-
/* @__PURE__ */
|
|
2073
|
-
/* @__PURE__ */
|
|
2074
|
-
/* @__PURE__ */
|
|
2075
|
-
/* @__PURE__ */
|
|
2404
|
+
return /* @__PURE__ */ jsxs7("div", { style: styles.darkContainer, children: [
|
|
2405
|
+
/* @__PURE__ */ jsx8(StepProgressBar, { total: 5, current: 3, isDark: true }),
|
|
2406
|
+
/* @__PURE__ */ jsxs7("div", { style: styles.darkScreenHeader, children: [
|
|
2407
|
+
/* @__PURE__ */ jsx8("div", { style: { width: 40 } }),
|
|
2408
|
+
/* @__PURE__ */ jsx8("h1", { style: styles.darkScreenTitle, children: "Flip your document" }),
|
|
2409
|
+
/* @__PURE__ */ jsx8("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2076
2410
|
] }),
|
|
2077
|
-
/* @__PURE__ */
|
|
2411
|
+
/* @__PURE__ */ jsxs7("div", { style: {
|
|
2078
2412
|
flex: 1,
|
|
2079
2413
|
display: "flex",
|
|
2080
2414
|
flexDirection: "column",
|
|
@@ -2083,7 +2417,7 @@ function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
|
2083
2417
|
padding: "24px",
|
|
2084
2418
|
gap: "32px"
|
|
2085
2419
|
}, children: [
|
|
2086
|
-
/* @__PURE__ */
|
|
2420
|
+
/* @__PURE__ */ jsx8("div", { style: {
|
|
2087
2421
|
width: "120px",
|
|
2088
2422
|
height: "120px",
|
|
2089
2423
|
borderRadius: "50%",
|
|
@@ -2091,18 +2425,18 @@ function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
|
2091
2425
|
display: "flex",
|
|
2092
2426
|
alignItems: "center",
|
|
2093
2427
|
justifyContent: "center"
|
|
2094
|
-
}, children: /* @__PURE__ */
|
|
2095
|
-
/* @__PURE__ */
|
|
2096
|
-
/* @__PURE__ */
|
|
2428
|
+
}, children: /* @__PURE__ */ jsxs7("svg", { width: "56", height: "56", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
2429
|
+
/* @__PURE__ */ jsx8("path", { d: "M9 3L5 6.99H8V14H10V6.99H13L9 3Z", fill: colors.teal }),
|
|
2430
|
+
/* @__PURE__ */ jsx8("path", { d: "M16 17.01V10H14V17.01H11L15 21L19 17.01H16Z", fill: colors.teal })
|
|
2097
2431
|
] }) }),
|
|
2098
|
-
/* @__PURE__ */
|
|
2099
|
-
/* @__PURE__ */
|
|
2432
|
+
/* @__PURE__ */ jsxs7("div", { style: { textAlign: "center" }, children: [
|
|
2433
|
+
/* @__PURE__ */ jsx8("h2", { style: {
|
|
2100
2434
|
fontSize: "22px",
|
|
2101
2435
|
fontWeight: 700,
|
|
2102
2436
|
color: colors.white,
|
|
2103
2437
|
margin: "0 0 12px 0"
|
|
2104
2438
|
}, children: "Now capture the back" }),
|
|
2105
|
-
/* @__PURE__ */
|
|
2439
|
+
/* @__PURE__ */ jsx8("p", { style: {
|
|
2106
2440
|
fontSize: "15px",
|
|
2107
2441
|
color: "rgba(255,255,255,0.6)",
|
|
2108
2442
|
margin: 0,
|
|
@@ -2110,38 +2444,38 @@ function FlipDocumentScreen({ onContinue, onCancel }) {
|
|
|
2110
2444
|
maxWidth: "280px"
|
|
2111
2445
|
}, children: "Turn your document over to the back side, then tap continue to take a photo." })
|
|
2112
2446
|
] }),
|
|
2113
|
-
/* @__PURE__ */
|
|
2114
|
-
/* @__PURE__ */
|
|
2447
|
+
/* @__PURE__ */ jsxs7("div", { style: styles.stepPillsRow, children: [
|
|
2448
|
+
/* @__PURE__ */ jsx8("span", { style: {
|
|
2115
2449
|
...styles.stepPill,
|
|
2116
2450
|
backgroundColor: "rgba(16,185,129,0.15)",
|
|
2117
2451
|
color: colors.success
|
|
2118
2452
|
}, children: "\u2713 Front" }),
|
|
2119
|
-
/* @__PURE__ */
|
|
2453
|
+
/* @__PURE__ */ jsx8("span", { style: {
|
|
2120
2454
|
...styles.stepPill,
|
|
2121
2455
|
backgroundColor: colors.teal,
|
|
2122
2456
|
color: colors.white
|
|
2123
2457
|
}, children: "Back" })
|
|
2124
2458
|
] })
|
|
2125
2459
|
] }),
|
|
2126
|
-
/* @__PURE__ */
|
|
2460
|
+
/* @__PURE__ */ jsx8("div", { style: { padding: "24px" }, children: /* @__PURE__ */ jsx8("button", { style: styles.primaryButton, onClick: onContinue, children: "Continue" }) })
|
|
2127
2461
|
] });
|
|
2128
2462
|
}
|
|
2129
2463
|
|
|
2130
2464
|
// src/components/SelfieCaptureScreen.tsx
|
|
2131
|
-
import { useRef as
|
|
2132
|
-
import { jsx as
|
|
2133
|
-
function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
2134
|
-
const videoRef =
|
|
2135
|
-
const canvasRef =
|
|
2136
|
-
const [stream, setStream] =
|
|
2137
|
-
const [isCapturing, setIsCapturing] =
|
|
2138
|
-
const [error, setError] =
|
|
2139
|
-
const [capturedImage, setCapturedImage] =
|
|
2140
|
-
const [capturedBlob, setCapturedBlob] =
|
|
2141
|
-
|
|
2465
|
+
import { useRef as useRef4, useEffect as useEffect7, useState as useState6, useCallback as useCallback3 } from "react";
|
|
2466
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2467
|
+
function SelfieCaptureScreen({ onCapture, onCancel, showVisualGuides = true }) {
|
|
2468
|
+
const videoRef = useRef4(null);
|
|
2469
|
+
const canvasRef = useRef4(null);
|
|
2470
|
+
const [stream, setStream] = useState6(null);
|
|
2471
|
+
const [isCapturing, setIsCapturing] = useState6(false);
|
|
2472
|
+
const [error, setError] = useState6(null);
|
|
2473
|
+
const [capturedImage, setCapturedImage] = useState6(null);
|
|
2474
|
+
const [capturedBlob, setCapturedBlob] = useState6(null);
|
|
2475
|
+
useEffect7(() => {
|
|
2142
2476
|
injectKeyframes();
|
|
2143
2477
|
}, []);
|
|
2144
|
-
|
|
2478
|
+
useEffect7(() => {
|
|
2145
2479
|
let mounted = true;
|
|
2146
2480
|
async function startCamera() {
|
|
2147
2481
|
try {
|
|
@@ -2163,7 +2497,7 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2163
2497
|
mounted = false;
|
|
2164
2498
|
};
|
|
2165
2499
|
}, [capturedImage]);
|
|
2166
|
-
|
|
2500
|
+
useEffect7(() => {
|
|
2167
2501
|
return () => {
|
|
2168
2502
|
stream?.getTracks().forEach((t) => t.stop());
|
|
2169
2503
|
};
|
|
@@ -2207,22 +2541,22 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2207
2541
|
}
|
|
2208
2542
|
};
|
|
2209
2543
|
if (error) {
|
|
2210
|
-
return /* @__PURE__ */
|
|
2211
|
-
/* @__PURE__ */
|
|
2212
|
-
/* @__PURE__ */
|
|
2544
|
+
return /* @__PURE__ */ jsx9("div", { style: styles.container, children: /* @__PURE__ */ jsxs8("div", { style: styles.errorContainer, children: [
|
|
2545
|
+
/* @__PURE__ */ jsx9("p", { style: styles.errorText, children: error }),
|
|
2546
|
+
/* @__PURE__ */ jsx9("button", { style: styles.primaryButton, onClick: onCancel, children: "Go Back" })
|
|
2213
2547
|
] }) });
|
|
2214
2548
|
}
|
|
2215
2549
|
if (capturedImage) {
|
|
2216
|
-
return /* @__PURE__ */
|
|
2217
|
-
/* @__PURE__ */
|
|
2218
|
-
/* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2220
|
-
/* @__PURE__ */
|
|
2221
|
-
/* @__PURE__ */
|
|
2550
|
+
return /* @__PURE__ */ jsxs8("div", { style: styles.darkContainer, children: [
|
|
2551
|
+
/* @__PURE__ */ jsx9(StepProgressBar, { total: 5, current: 4, isDark: true }),
|
|
2552
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.darkScreenHeader, children: [
|
|
2553
|
+
/* @__PURE__ */ jsx9("div", { style: { width: 40 } }),
|
|
2554
|
+
/* @__PURE__ */ jsx9("h1", { style: styles.darkScreenTitle, children: "Does this look like you?" }),
|
|
2555
|
+
/* @__PURE__ */ jsx9("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2222
2556
|
] }),
|
|
2223
|
-
/* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2557
|
+
/* @__PURE__ */ jsx9("p", { style: styles.darkScreenSubtitle, children: "Check clarity and lighting" }),
|
|
2558
|
+
/* @__PURE__ */ jsx9("div", { style: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "24px" }, children: /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
|
|
2559
|
+
/* @__PURE__ */ jsx9("div", { style: { width: "240px", height: "300px", borderRadius: "50%", overflow: "hidden", border: `3px solid ${colors.teal}` }, children: /* @__PURE__ */ jsx9(
|
|
2226
2560
|
"img",
|
|
2227
2561
|
{
|
|
2228
2562
|
src: capturedImage,
|
|
@@ -2230,31 +2564,32 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2230
2564
|
style: { width: "100%", height: "100%", objectFit: "cover" }
|
|
2231
2565
|
}
|
|
2232
2566
|
) }),
|
|
2233
|
-
/* @__PURE__ */
|
|
2234
|
-
/* @__PURE__ */
|
|
2235
|
-
/* @__PURE__ */
|
|
2236
|
-
/* @__PURE__ */
|
|
2237
|
-
/* @__PURE__ */
|
|
2567
|
+
/* @__PURE__ */ jsx9("div", { style: { textAlign: "center", marginTop: "16px" }, children: /* @__PURE__ */ jsx9("span", { style: styles.reviewBadge, children: "\u2713 Face detected" }) }),
|
|
2568
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.qualityChecks, children: [
|
|
2569
|
+
/* @__PURE__ */ jsx9(QualityCheck2, { label: "Clear" }),
|
|
2570
|
+
/* @__PURE__ */ jsx9(QualityCheck2, { label: "Centered" }),
|
|
2571
|
+
/* @__PURE__ */ jsx9(QualityCheck2, { label: "Well-lit" })
|
|
2238
2572
|
] })
|
|
2239
2573
|
] }) }),
|
|
2240
|
-
/* @__PURE__ */
|
|
2241
|
-
/* @__PURE__ */
|
|
2242
|
-
/* @__PURE__ */
|
|
2574
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.reviewButtonsRow, children: [
|
|
2575
|
+
/* @__PURE__ */ jsx9("button", { style: { ...styles.darkOutlineButton, flex: 1 }, onClick: handleRetake, children: "Retake" }),
|
|
2576
|
+
/* @__PURE__ */ jsx9("button", { style: { ...styles.primaryButton, flex: 1 }, onClick: handleAccept, children: "Use this" })
|
|
2243
2577
|
] })
|
|
2244
2578
|
] });
|
|
2245
2579
|
}
|
|
2246
|
-
return /* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2580
|
+
return /* @__PURE__ */ jsxs8("div", { style: styles.captureContainer, children: [
|
|
2581
|
+
/* @__PURE__ */ jsx9(StepProgressBar, { total: 5, current: 4, isDark: true }),
|
|
2582
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.darkScreenHeader, children: [
|
|
2583
|
+
/* @__PURE__ */ jsx9("div", { style: { width: 40 } }),
|
|
2584
|
+
/* @__PURE__ */ jsxs8("div", { style: { flex: 1, textAlign: "center" }, children: [
|
|
2585
|
+
/* @__PURE__ */ jsx9("h1", { style: { ...styles.darkScreenTitle, margin: 0, fontSize: "24px", fontWeight: 700 }, children: "Face the camera" }),
|
|
2586
|
+
/* @__PURE__ */ jsx9("p", { style: styles.darkScreenSubtitle, children: "Keep a neutral expression" })
|
|
2253
2587
|
] }),
|
|
2254
|
-
/* @__PURE__ */
|
|
2588
|
+
/* @__PURE__ */ jsx9("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2255
2589
|
] }),
|
|
2256
|
-
/* @__PURE__ */
|
|
2257
|
-
|
|
2590
|
+
showVisualGuides && /* @__PURE__ */ jsx9("div", { style: { display: "flex", justifyContent: "center", padding: "6px 0 0" }, children: /* @__PURE__ */ jsx9(VisualGuide, { kind: "selfie", size: 56 }) }),
|
|
2591
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.cameraContainer, children: [
|
|
2592
|
+
/* @__PURE__ */ jsx9(
|
|
2258
2593
|
"video",
|
|
2259
2594
|
{
|
|
2260
2595
|
ref: videoRef,
|
|
@@ -2264,10 +2599,10 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2264
2599
|
style: { ...styles.cameraVideo, transform: "scaleX(-1)" }
|
|
2265
2600
|
}
|
|
2266
2601
|
),
|
|
2267
|
-
/* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2602
|
+
/* @__PURE__ */ jsx9("div", { style: styles.selfieOverlay, children: /* @__PURE__ */ jsx9("div", { style: styles.faceGuide, children: /* @__PURE__ */ jsx9("div", { style: styles.rotatingRing }) }) }),
|
|
2603
|
+
/* @__PURE__ */ jsx9("canvas", { ref: canvasRef, style: { display: "none" } })
|
|
2269
2604
|
] }),
|
|
2270
|
-
/* @__PURE__ */
|
|
2605
|
+
/* @__PURE__ */ jsx9("div", { style: { textAlign: "center", padding: "8px 0" }, children: /* @__PURE__ */ jsxs8(
|
|
2271
2606
|
"span",
|
|
2272
2607
|
{
|
|
2273
2608
|
style: {
|
|
@@ -2276,32 +2611,88 @@ function SelfieCaptureScreen({ onCapture, onCancel }) {
|
|
|
2276
2611
|
color: colors.teal
|
|
2277
2612
|
},
|
|
2278
2613
|
children: [
|
|
2279
|
-
/* @__PURE__ */
|
|
2614
|
+
/* @__PURE__ */ jsx9("span", { style: { ...styles.pulsingDot, backgroundColor: colors.teal } }),
|
|
2280
2615
|
"Position your face in the oval"
|
|
2281
2616
|
]
|
|
2282
2617
|
}
|
|
2283
2618
|
) }),
|
|
2284
|
-
/* @__PURE__ */
|
|
2619
|
+
/* @__PURE__ */ jsx9("div", { style: styles.captureFooter, children: /* @__PURE__ */ jsx9(
|
|
2285
2620
|
"button",
|
|
2286
2621
|
{
|
|
2287
2622
|
style: { ...styles.captureButton, opacity: isCapturing ? 0.5 : 1 },
|
|
2288
2623
|
onClick: handleCapture,
|
|
2289
2624
|
disabled: isCapturing,
|
|
2290
|
-
children: /* @__PURE__ */
|
|
2625
|
+
children: /* @__PURE__ */ jsx9("div", { style: styles.captureButtonInner })
|
|
2291
2626
|
}
|
|
2292
2627
|
) })
|
|
2293
2628
|
] });
|
|
2294
2629
|
}
|
|
2295
2630
|
function QualityCheck2({ label }) {
|
|
2296
|
-
return /* @__PURE__ */
|
|
2297
|
-
/* @__PURE__ */
|
|
2298
|
-
/* @__PURE__ */
|
|
2631
|
+
return /* @__PURE__ */ jsxs8("div", { style: styles.qualityCheck, children: [
|
|
2632
|
+
/* @__PURE__ */ jsx9("div", { style: styles.qualityCheckIcon, children: "\u2713" }),
|
|
2633
|
+
/* @__PURE__ */ jsx9("span", { style: styles.qualityCheckLabel, children: label })
|
|
2299
2634
|
] });
|
|
2300
2635
|
}
|
|
2301
2636
|
|
|
2302
2637
|
// src/components/LivenessScreen.tsx
|
|
2303
|
-
import { useEffect as
|
|
2304
|
-
|
|
2638
|
+
import { useEffect as useEffect9, useRef as useRef6, useState as useState8, useCallback as useCallback4 } from "react";
|
|
2639
|
+
|
|
2640
|
+
// src/hooks/useLivenessSignals.ts
|
|
2641
|
+
import { useEffect as useEffect8, useRef as useRef5, useState as useState7 } from "react";
|
|
2642
|
+
var FRAME_INTERVAL_MS2 = 250;
|
|
2643
|
+
function useLivenessSignals(videoRef) {
|
|
2644
|
+
const [signals, setSignals] = useState7({
|
|
2645
|
+
faceDetected: false,
|
|
2646
|
+
detectorActive: false
|
|
2647
|
+
});
|
|
2648
|
+
const detectorRef = useRef5(null);
|
|
2649
|
+
const intervalRef = useRef5(null);
|
|
2650
|
+
useEffect8(() => {
|
|
2651
|
+
let cancelled = false;
|
|
2652
|
+
async function setupDetector() {
|
|
2653
|
+
const NativeFaceDetector = typeof window !== "undefined" && "FaceDetector" in window ? window.FaceDetector : null;
|
|
2654
|
+
if (!NativeFaceDetector) {
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
try {
|
|
2658
|
+
const detector = new NativeFaceDetector({ fastMode: true, maxDetectedFaces: 1 });
|
|
2659
|
+
if (cancelled) return;
|
|
2660
|
+
detectorRef.current = detector;
|
|
2661
|
+
setSignals((prev) => ({ ...prev, detectorActive: true }));
|
|
2662
|
+
} catch {
|
|
2663
|
+
return;
|
|
2664
|
+
}
|
|
2665
|
+
intervalRef.current = setInterval(async () => {
|
|
2666
|
+
const detector = detectorRef.current;
|
|
2667
|
+
const video = videoRef.current;
|
|
2668
|
+
if (!detector || !video || video.readyState < 2) return;
|
|
2669
|
+
try {
|
|
2670
|
+
const faces = await detector.detect(video);
|
|
2671
|
+
if (cancelled) return;
|
|
2672
|
+
setSignals((prev) => {
|
|
2673
|
+
const next = faces.length > 0;
|
|
2674
|
+
if (prev.faceDetected === next) return prev;
|
|
2675
|
+
return { ...prev, faceDetected: next };
|
|
2676
|
+
});
|
|
2677
|
+
} catch {
|
|
2678
|
+
}
|
|
2679
|
+
}, FRAME_INTERVAL_MS2);
|
|
2680
|
+
}
|
|
2681
|
+
setupDetector();
|
|
2682
|
+
return () => {
|
|
2683
|
+
cancelled = true;
|
|
2684
|
+
if (intervalRef.current) {
|
|
2685
|
+
clearInterval(intervalRef.current);
|
|
2686
|
+
intervalRef.current = null;
|
|
2687
|
+
}
|
|
2688
|
+
detectorRef.current = null;
|
|
2689
|
+
};
|
|
2690
|
+
}, [videoRef]);
|
|
2691
|
+
return signals;
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
// src/components/LivenessScreen.tsx
|
|
2695
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2305
2696
|
function LivenessScreen({
|
|
2306
2697
|
session,
|
|
2307
2698
|
currentChallenge,
|
|
@@ -2309,22 +2700,25 @@ function LivenessScreen({
|
|
|
2309
2700
|
onChallengeComplete,
|
|
2310
2701
|
onStart,
|
|
2311
2702
|
onComplete,
|
|
2312
|
-
onCancel
|
|
2703
|
+
onCancel,
|
|
2704
|
+
lastChallengeError,
|
|
2705
|
+
showVisualGuides = true
|
|
2313
2706
|
}) {
|
|
2314
|
-
const videoRef =
|
|
2315
|
-
const canvasRef =
|
|
2316
|
-
const [stream, setStream] =
|
|
2317
|
-
const
|
|
2318
|
-
const [
|
|
2319
|
-
const [
|
|
2320
|
-
const [
|
|
2321
|
-
|
|
2707
|
+
const videoRef = useRef6(null);
|
|
2708
|
+
const canvasRef = useRef6(null);
|
|
2709
|
+
const [stream, setStream] = useState8(null);
|
|
2710
|
+
const livenessSignals = useLivenessSignals(videoRef);
|
|
2711
|
+
const [cameraError, setCameraError] = useState8(null);
|
|
2712
|
+
const [phase, setPhase] = useState8("preparing");
|
|
2713
|
+
const [countdown, setCountdown] = useState8(3);
|
|
2714
|
+
const [capturing, setCapturing] = useState8(false);
|
|
2715
|
+
useEffect9(() => {
|
|
2322
2716
|
injectKeyframes();
|
|
2323
2717
|
}, []);
|
|
2324
|
-
|
|
2718
|
+
useEffect9(() => {
|
|
2325
2719
|
if (!session) onStart();
|
|
2326
2720
|
}, [session, onStart]);
|
|
2327
|
-
|
|
2721
|
+
useEffect9(() => {
|
|
2328
2722
|
let mounted = true;
|
|
2329
2723
|
async function startCamera() {
|
|
2330
2724
|
try {
|
|
@@ -2356,12 +2750,12 @@ function LivenessScreen({
|
|
|
2356
2750
|
mounted = false;
|
|
2357
2751
|
};
|
|
2358
2752
|
}, []);
|
|
2359
|
-
|
|
2753
|
+
useEffect9(() => {
|
|
2360
2754
|
return () => {
|
|
2361
2755
|
stream?.getTracks().forEach((t) => t.stop());
|
|
2362
2756
|
};
|
|
2363
2757
|
}, [stream]);
|
|
2364
|
-
|
|
2758
|
+
useEffect9(() => {
|
|
2365
2759
|
if (!currentChallenge) return;
|
|
2366
2760
|
setPhase("preparing");
|
|
2367
2761
|
setCountdown(3);
|
|
@@ -2389,7 +2783,7 @@ function LivenessScreen({
|
|
|
2389
2783
|
0.85
|
|
2390
2784
|
);
|
|
2391
2785
|
}, [currentChallenge, capturing, onChallengeComplete]);
|
|
2392
|
-
|
|
2786
|
+
useEffect9(() => {
|
|
2393
2787
|
if (!currentChallenge || capturing) return;
|
|
2394
2788
|
if (countdown === 0) {
|
|
2395
2789
|
if (phase === "preparing") {
|
|
@@ -2403,32 +2797,32 @@ function LivenessScreen({
|
|
|
2403
2797
|
const t = setTimeout(() => setCountdown((c) => c - 1), 1e3);
|
|
2404
2798
|
return () => clearTimeout(t);
|
|
2405
2799
|
}, [countdown, currentChallenge?.id, capturing, captureFrame, phase]);
|
|
2406
|
-
|
|
2800
|
+
useEffect9(() => {
|
|
2407
2801
|
if (session && !currentChallenge && completedChallenges > 0) {
|
|
2408
2802
|
onComplete();
|
|
2409
2803
|
}
|
|
2410
2804
|
}, [session, currentChallenge, completedChallenges, onComplete]);
|
|
2411
2805
|
if (cameraError) {
|
|
2412
|
-
return /* @__PURE__ */
|
|
2413
|
-
/* @__PURE__ */
|
|
2414
|
-
/* @__PURE__ */
|
|
2806
|
+
return /* @__PURE__ */ jsx10("div", { style: styles.darkContainer, children: /* @__PURE__ */ jsxs9("div", { style: styles.errorContainer, children: [
|
|
2807
|
+
/* @__PURE__ */ jsx10("p", { style: styles.errorText, children: cameraError }),
|
|
2808
|
+
/* @__PURE__ */ jsx10("button", { style: styles.primaryButton, onClick: onCancel, children: "Go back" })
|
|
2415
2809
|
] }) });
|
|
2416
2810
|
}
|
|
2417
2811
|
if (!session) {
|
|
2418
|
-
return /* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2812
|
+
return /* @__PURE__ */ jsx10("div", { style: styles.darkContainer, children: /* @__PURE__ */ jsxs9("div", { style: styles.loadingContainer, children: [
|
|
2813
|
+
/* @__PURE__ */ jsx10("div", { style: styles.spinner }),
|
|
2814
|
+
/* @__PURE__ */ jsx10("p", { style: { ...styles.loadingText, color: "rgba(255,255,255,0.6)" }, children: "Starting liveness check..." })
|
|
2421
2815
|
] }) });
|
|
2422
2816
|
}
|
|
2423
2817
|
const totalChallenges = session.challenges.length;
|
|
2424
|
-
return /* @__PURE__ */
|
|
2425
|
-
/* @__PURE__ */
|
|
2426
|
-
/* @__PURE__ */
|
|
2427
|
-
/* @__PURE__ */
|
|
2428
|
-
/* @__PURE__ */
|
|
2429
|
-
/* @__PURE__ */
|
|
2818
|
+
return /* @__PURE__ */ jsxs9("div", { style: styles.captureContainer, children: [
|
|
2819
|
+
/* @__PURE__ */ jsx10(StepProgressBar, { total: 5, current: 5, isDark: true }),
|
|
2820
|
+
/* @__PURE__ */ jsxs9("div", { style: styles.darkScreenHeader, children: [
|
|
2821
|
+
/* @__PURE__ */ jsx10("div", { style: { width: 40 } }),
|
|
2822
|
+
/* @__PURE__ */ jsx10("h1", { style: styles.darkScreenTitle, children: "Liveness Check" }),
|
|
2823
|
+
/* @__PURE__ */ jsx10("button", { style: styles.glassCloseButton, onClick: onCancel, children: "\u2715" })
|
|
2430
2824
|
] }),
|
|
2431
|
-
/* @__PURE__ */
|
|
2825
|
+
/* @__PURE__ */ jsxs9(
|
|
2432
2826
|
"div",
|
|
2433
2827
|
{
|
|
2434
2828
|
style: {
|
|
@@ -2441,8 +2835,8 @@ function LivenessScreen({
|
|
|
2441
2835
|
padding: "16px 0"
|
|
2442
2836
|
},
|
|
2443
2837
|
children: [
|
|
2444
|
-
/* @__PURE__ */
|
|
2445
|
-
/* @__PURE__ */
|
|
2838
|
+
/* @__PURE__ */ jsxs9("div", { style: { position: "relative" }, children: [
|
|
2839
|
+
/* @__PURE__ */ jsx10(
|
|
2446
2840
|
"div",
|
|
2447
2841
|
{
|
|
2448
2842
|
style: {
|
|
@@ -2453,7 +2847,7 @@ function LivenessScreen({
|
|
|
2453
2847
|
backgroundColor: "#000",
|
|
2454
2848
|
border: "3px solid rgba(255,255,255,0.2)"
|
|
2455
2849
|
},
|
|
2456
|
-
children: /* @__PURE__ */
|
|
2850
|
+
children: /* @__PURE__ */ jsx10(
|
|
2457
2851
|
"video",
|
|
2458
2852
|
{
|
|
2459
2853
|
ref: videoRef,
|
|
@@ -2470,7 +2864,7 @@ function LivenessScreen({
|
|
|
2470
2864
|
)
|
|
2471
2865
|
}
|
|
2472
2866
|
),
|
|
2473
|
-
/* @__PURE__ */
|
|
2867
|
+
/* @__PURE__ */ jsx10(
|
|
2474
2868
|
"svg",
|
|
2475
2869
|
{
|
|
2476
2870
|
style: {
|
|
@@ -2482,7 +2876,7 @@ function LivenessScreen({
|
|
|
2482
2876
|
width: "256",
|
|
2483
2877
|
height: "316",
|
|
2484
2878
|
viewBox: "0 0 256 316",
|
|
2485
|
-
children: /* @__PURE__ */
|
|
2879
|
+
children: /* @__PURE__ */ jsx10(
|
|
2486
2880
|
"ellipse",
|
|
2487
2881
|
{
|
|
2488
2882
|
cx: "128",
|
|
@@ -2498,9 +2892,30 @@ function LivenessScreen({
|
|
|
2498
2892
|
}
|
|
2499
2893
|
)
|
|
2500
2894
|
}
|
|
2895
|
+
),
|
|
2896
|
+
livenessSignals.detectorActive && /* @__PURE__ */ jsx10(
|
|
2897
|
+
"div",
|
|
2898
|
+
{
|
|
2899
|
+
style: {
|
|
2900
|
+
position: "absolute",
|
|
2901
|
+
bottom: "-32px",
|
|
2902
|
+
left: "50%",
|
|
2903
|
+
transform: "translateX(-50%)",
|
|
2904
|
+
padding: "6px 14px",
|
|
2905
|
+
borderRadius: "999px",
|
|
2906
|
+
fontSize: "12px",
|
|
2907
|
+
fontWeight: 600,
|
|
2908
|
+
color: livenessSignals.faceDetected ? colors.success : "rgba(255,255,255,0.55)",
|
|
2909
|
+
backgroundColor: livenessSignals.faceDetected ? "rgba(16,185,129,0.15)" : "rgba(255,255,255,0.06)",
|
|
2910
|
+
border: livenessSignals.faceDetected ? "1px solid rgba(16,185,129,0.4)" : "1px solid rgba(255,255,255,0.12)",
|
|
2911
|
+
transition: "all 200ms",
|
|
2912
|
+
whiteSpace: "nowrap"
|
|
2913
|
+
},
|
|
2914
|
+
children: livenessSignals.faceDetected ? "\u2713 Face detected" : "Position your face in the oval"
|
|
2915
|
+
}
|
|
2501
2916
|
)
|
|
2502
2917
|
] }),
|
|
2503
|
-
currentChallenge && /* @__PURE__ */
|
|
2918
|
+
currentChallenge && /* @__PURE__ */ jsxs9(
|
|
2504
2919
|
"div",
|
|
2505
2920
|
{
|
|
2506
2921
|
style: {
|
|
@@ -2513,7 +2928,14 @@ function LivenessScreen({
|
|
|
2513
2928
|
transition: "background-color 200ms, border-color 200ms"
|
|
2514
2929
|
},
|
|
2515
2930
|
children: [
|
|
2516
|
-
/* @__PURE__ */
|
|
2931
|
+
showVisualGuides && visualGuideForChallenge(currentChallenge.type) && /* @__PURE__ */ jsx10("div", { style: { display: "flex", justifyContent: "center", marginBottom: "12px" }, children: /* @__PURE__ */ jsx10(
|
|
2932
|
+
VisualGuide,
|
|
2933
|
+
{
|
|
2934
|
+
kind: visualGuideForChallenge(currentChallenge.type),
|
|
2935
|
+
size: 64
|
|
2936
|
+
}
|
|
2937
|
+
) }),
|
|
2938
|
+
/* @__PURE__ */ jsx10(
|
|
2517
2939
|
"p",
|
|
2518
2940
|
{
|
|
2519
2941
|
style: {
|
|
@@ -2527,7 +2949,7 @@ function LivenessScreen({
|
|
|
2527
2949
|
children: capturing ? "Checking..." : phase === "preparing" ? "Get ready" : "Now \u2014 hold the pose"
|
|
2528
2950
|
}
|
|
2529
2951
|
),
|
|
2530
|
-
/* @__PURE__ */
|
|
2952
|
+
/* @__PURE__ */ jsx10(
|
|
2531
2953
|
"h2",
|
|
2532
2954
|
{
|
|
2533
2955
|
style: {
|
|
@@ -2538,7 +2960,7 @@ function LivenessScreen({
|
|
|
2538
2960
|
children: currentChallenge.instruction
|
|
2539
2961
|
}
|
|
2540
2962
|
),
|
|
2541
|
-
!capturing && /* @__PURE__ */
|
|
2963
|
+
!capturing && /* @__PURE__ */ jsx10(
|
|
2542
2964
|
"p",
|
|
2543
2965
|
{
|
|
2544
2966
|
style: {
|
|
@@ -2550,16 +2972,33 @@ function LivenessScreen({
|
|
|
2550
2972
|
},
|
|
2551
2973
|
children: countdown
|
|
2552
2974
|
}
|
|
2975
|
+
),
|
|
2976
|
+
lastChallengeError && phase === "preparing" && !capturing && /* @__PURE__ */ jsx10(
|
|
2977
|
+
"p",
|
|
2978
|
+
{
|
|
2979
|
+
style: {
|
|
2980
|
+
margin: "14px 0 0",
|
|
2981
|
+
padding: "10px 12px",
|
|
2982
|
+
borderRadius: "10px",
|
|
2983
|
+
fontSize: "13px",
|
|
2984
|
+
fontWeight: 500,
|
|
2985
|
+
color: "#fca5a5",
|
|
2986
|
+
backgroundColor: "rgba(239,68,68,0.10)",
|
|
2987
|
+
border: "1px solid rgba(239,68,68,0.25)",
|
|
2988
|
+
lineHeight: 1.35
|
|
2989
|
+
},
|
|
2990
|
+
children: lastChallengeError
|
|
2991
|
+
}
|
|
2553
2992
|
)
|
|
2554
2993
|
]
|
|
2555
2994
|
}
|
|
2556
2995
|
),
|
|
2557
|
-
/* @__PURE__ */
|
|
2996
|
+
/* @__PURE__ */ jsx10("canvas", { ref: canvasRef, style: { display: "none" } })
|
|
2558
2997
|
]
|
|
2559
2998
|
}
|
|
2560
2999
|
),
|
|
2561
|
-
/* @__PURE__ */
|
|
2562
|
-
/* @__PURE__ */
|
|
3000
|
+
/* @__PURE__ */ jsxs9("div", { style: { padding: "16px 0" }, children: [
|
|
3001
|
+
/* @__PURE__ */ jsx10("div", { style: styles.progressDots, children: session.challenges.map((_, index) => /* @__PURE__ */ jsx10(
|
|
2563
3002
|
"div",
|
|
2564
3003
|
{
|
|
2565
3004
|
style: {
|
|
@@ -2569,7 +3008,7 @@ function LivenessScreen({
|
|
|
2569
3008
|
},
|
|
2570
3009
|
index
|
|
2571
3010
|
)) }),
|
|
2572
|
-
/* @__PURE__ */
|
|
3011
|
+
/* @__PURE__ */ jsxs9("p", { style: styles.progressText, children: [
|
|
2573
3012
|
"Challenge ",
|
|
2574
3013
|
Math.min(completedChallenges + 1, totalChallenges),
|
|
2575
3014
|
" of",
|
|
@@ -2577,7 +3016,7 @@ function LivenessScreen({
|
|
|
2577
3016
|
totalChallenges
|
|
2578
3017
|
] })
|
|
2579
3018
|
] }),
|
|
2580
|
-
/* @__PURE__ */
|
|
3019
|
+
/* @__PURE__ */ jsx10("div", { style: { padding: "0 24px 24px", textAlign: "center" }, children: /* @__PURE__ */ jsx10(
|
|
2581
3020
|
"p",
|
|
2582
3021
|
{
|
|
2583
3022
|
style: {
|
|
@@ -2592,35 +3031,35 @@ function LivenessScreen({
|
|
|
2592
3031
|
}
|
|
2593
3032
|
|
|
2594
3033
|
// src/components/ResultScreen.tsx
|
|
2595
|
-
import { jsx as
|
|
3034
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2596
3035
|
function ResultScreen({ verification, onDone, onRetry, resultPageMode, simplified, customMessages }) {
|
|
2597
3036
|
const { status } = verification;
|
|
2598
3037
|
const effectiveMode = resultPageMode ?? (simplified ? "simplified" : "detailed");
|
|
2599
3038
|
if (effectiveMode === "simplified") {
|
|
2600
3039
|
switch (status) {
|
|
2601
3040
|
case "approved":
|
|
2602
|
-
return /* @__PURE__ */
|
|
3041
|
+
return /* @__PURE__ */ jsx11(SimplifiedSuccess, { onDone, customMessages });
|
|
2603
3042
|
case "rejected":
|
|
2604
|
-
return /* @__PURE__ */
|
|
3043
|
+
return /* @__PURE__ */ jsx11(SimplifiedFailed, { onRetry: onRetry || onDone, customMessages });
|
|
2605
3044
|
case "review_required":
|
|
2606
|
-
return /* @__PURE__ */
|
|
3045
|
+
return /* @__PURE__ */ jsx11(SimplifiedReview, { verification, onDone, customMessages });
|
|
2607
3046
|
case "expired":
|
|
2608
|
-
return /* @__PURE__ */
|
|
3047
|
+
return /* @__PURE__ */ jsx11(SimplifiedFailed, { onRetry: onRetry || onDone, customMessages: { failedTitle: "Document Expired", failedMessage: "The document you submitted has expired. Please use a valid document." } });
|
|
2609
3048
|
default:
|
|
2610
|
-
return /* @__PURE__ */
|
|
3049
|
+
return /* @__PURE__ */ jsx11(SimplifiedSuccess, { onDone, customMessages });
|
|
2611
3050
|
}
|
|
2612
3051
|
}
|
|
2613
3052
|
switch (status) {
|
|
2614
3053
|
case "approved":
|
|
2615
|
-
return /* @__PURE__ */
|
|
3054
|
+
return /* @__PURE__ */ jsx11(SuccessResult, { verification, onDone });
|
|
2616
3055
|
case "rejected":
|
|
2617
|
-
return /* @__PURE__ */
|
|
3056
|
+
return /* @__PURE__ */ jsx11(RejectedResult, { verification, onRetry: onRetry || onDone });
|
|
2618
3057
|
case "expired":
|
|
2619
|
-
return /* @__PURE__ */
|
|
3058
|
+
return /* @__PURE__ */ jsx11(ExpiredResult, { verification, onRetry: onRetry || onDone });
|
|
2620
3059
|
case "review_required":
|
|
2621
|
-
return /* @__PURE__ */
|
|
3060
|
+
return /* @__PURE__ */ jsx11(ManualReviewResult, { verification, onDone });
|
|
2622
3061
|
default:
|
|
2623
|
-
return /* @__PURE__ */
|
|
3062
|
+
return /* @__PURE__ */ jsx11(SuccessResult, { verification, onDone });
|
|
2624
3063
|
}
|
|
2625
3064
|
}
|
|
2626
3065
|
function SuccessResult({ verification, onDone }) {
|
|
@@ -2628,16 +3067,16 @@ function SuccessResult({ verification, onDone }) {
|
|
|
2628
3067
|
verification.scores?.overall ?? 100 - (verification.riskScore ?? 16)
|
|
2629
3068
|
);
|
|
2630
3069
|
const metrics = computeScoreBreakdown(verification);
|
|
2631
|
-
return /* @__PURE__ */
|
|
2632
|
-
/* @__PURE__ */
|
|
2633
|
-
/* @__PURE__ */
|
|
3070
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3071
|
+
/* @__PURE__ */ jsxs10("div", { style: styles.resultContent, children: [
|
|
3072
|
+
/* @__PURE__ */ jsx11(
|
|
2634
3073
|
"div",
|
|
2635
3074
|
{
|
|
2636
3075
|
style: {
|
|
2637
3076
|
...styles.resultIconOuterRing,
|
|
2638
3077
|
backgroundColor: `${colors.success}15`
|
|
2639
3078
|
},
|
|
2640
|
-
children: /* @__PURE__ */
|
|
3079
|
+
children: /* @__PURE__ */ jsx11(
|
|
2641
3080
|
"div",
|
|
2642
3081
|
{
|
|
2643
3082
|
style: {
|
|
@@ -2651,9 +3090,9 @@ function SuccessResult({ verification, onDone }) {
|
|
|
2651
3090
|
)
|
|
2652
3091
|
}
|
|
2653
3092
|
),
|
|
2654
|
-
/* @__PURE__ */
|
|
2655
|
-
/* @__PURE__ */
|
|
2656
|
-
/* @__PURE__ */
|
|
3093
|
+
/* @__PURE__ */ jsx11("h1", { style: styles.resultTitle, children: "Verification approved" }),
|
|
3094
|
+
/* @__PURE__ */ jsx11("p", { style: styles.resultSubtitle, children: "Your identity has been successfully verified." }),
|
|
3095
|
+
/* @__PURE__ */ jsx11(
|
|
2657
3096
|
ScoreCard,
|
|
2658
3097
|
{
|
|
2659
3098
|
score,
|
|
@@ -2661,9 +3100,9 @@ function SuccessResult({ verification, onDone }) {
|
|
|
2661
3100
|
gradient: `linear-gradient(135deg, ${colors.teal}, ${colors.tealDark})`
|
|
2662
3101
|
}
|
|
2663
3102
|
),
|
|
2664
|
-
metrics.map((m, i) => /* @__PURE__ */
|
|
3103
|
+
metrics.map((m, i) => /* @__PURE__ */ jsx11(ScoreMetricRow, { ...m }, i))
|
|
2665
3104
|
] }),
|
|
2666
|
-
/* @__PURE__ */
|
|
3105
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onDone, children: "Done" }) })
|
|
2667
3106
|
] });
|
|
2668
3107
|
}
|
|
2669
3108
|
function RejectedResult({ verification, onRetry }) {
|
|
@@ -2671,16 +3110,16 @@ function RejectedResult({ verification, onRetry }) {
|
|
|
2671
3110
|
verification.scores?.overall ?? 100 - (verification.riskScore ?? 58)
|
|
2672
3111
|
);
|
|
2673
3112
|
const metrics = computeScoreBreakdown(verification);
|
|
2674
|
-
return /* @__PURE__ */
|
|
2675
|
-
/* @__PURE__ */
|
|
2676
|
-
/* @__PURE__ */
|
|
3113
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3114
|
+
/* @__PURE__ */ jsxs10("div", { style: styles.resultContent, children: [
|
|
3115
|
+
/* @__PURE__ */ jsx11(
|
|
2677
3116
|
"div",
|
|
2678
3117
|
{
|
|
2679
3118
|
style: {
|
|
2680
3119
|
...styles.resultIconOuterRing,
|
|
2681
3120
|
backgroundColor: `${colors.error}15`
|
|
2682
3121
|
},
|
|
2683
|
-
children: /* @__PURE__ */
|
|
3122
|
+
children: /* @__PURE__ */ jsx11(
|
|
2684
3123
|
"div",
|
|
2685
3124
|
{
|
|
2686
3125
|
style: {
|
|
@@ -2694,9 +3133,9 @@ function RejectedResult({ verification, onRetry }) {
|
|
|
2694
3133
|
)
|
|
2695
3134
|
}
|
|
2696
3135
|
),
|
|
2697
|
-
/* @__PURE__ */
|
|
2698
|
-
/* @__PURE__ */
|
|
2699
|
-
/* @__PURE__ */
|
|
3136
|
+
/* @__PURE__ */ jsx11("h1", { style: styles.resultTitle, children: "Verification rejected" }),
|
|
3137
|
+
/* @__PURE__ */ jsx11("p", { style: styles.resultSubtitle, children: "We could not verify your identity. Please try again with a valid document." }),
|
|
3138
|
+
/* @__PURE__ */ jsx11(
|
|
2700
3139
|
ScoreCard,
|
|
2701
3140
|
{
|
|
2702
3141
|
score,
|
|
@@ -2704,15 +3143,15 @@ function RejectedResult({ verification, onRetry }) {
|
|
|
2704
3143
|
gradient: `linear-gradient(135deg, ${colors.error}, #B91C1C)`
|
|
2705
3144
|
}
|
|
2706
3145
|
),
|
|
2707
|
-
metrics.map((m, i) => /* @__PURE__ */
|
|
3146
|
+
metrics.map((m, i) => /* @__PURE__ */ jsx11(ScoreMetricRow, { ...m }, i))
|
|
2708
3147
|
] }),
|
|
2709
|
-
/* @__PURE__ */
|
|
3148
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onRetry, children: "Try again" }) })
|
|
2710
3149
|
] });
|
|
2711
3150
|
}
|
|
2712
3151
|
function ExpiredResult({ verification, onRetry }) {
|
|
2713
|
-
return /* @__PURE__ */
|
|
2714
|
-
/* @__PURE__ */
|
|
2715
|
-
/* @__PURE__ */
|
|
3152
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3153
|
+
/* @__PURE__ */ jsxs10("div", { style: styles.resultContent, children: [
|
|
3154
|
+
/* @__PURE__ */ jsx11(
|
|
2716
3155
|
"div",
|
|
2717
3156
|
{
|
|
2718
3157
|
style: {
|
|
@@ -2720,7 +3159,7 @@ function ExpiredResult({ verification, onRetry }) {
|
|
|
2720
3159
|
backgroundColor: `${colors.warning}15`,
|
|
2721
3160
|
border: `2px solid ${colors.warning}30`
|
|
2722
3161
|
},
|
|
2723
|
-
children: /* @__PURE__ */
|
|
3162
|
+
children: /* @__PURE__ */ jsx11(
|
|
2724
3163
|
"div",
|
|
2725
3164
|
{
|
|
2726
3165
|
style: {
|
|
@@ -2734,29 +3173,29 @@ function ExpiredResult({ verification, onRetry }) {
|
|
|
2734
3173
|
)
|
|
2735
3174
|
}
|
|
2736
3175
|
),
|
|
2737
|
-
/* @__PURE__ */
|
|
2738
|
-
/* @__PURE__ */
|
|
2739
|
-
verification.documentVerification && /* @__PURE__ */
|
|
2740
|
-
/* @__PURE__ */
|
|
2741
|
-
/* @__PURE__ */
|
|
2742
|
-
/* @__PURE__ */
|
|
3176
|
+
/* @__PURE__ */ jsx11("h1", { style: styles.resultTitle, children: "Document expired" }),
|
|
3177
|
+
/* @__PURE__ */ jsx11("p", { style: styles.resultSubtitle, children: "The document you submitted has expired. Please use a valid, non-expired document." }),
|
|
3178
|
+
verification.documentVerification && /* @__PURE__ */ jsxs10("div", { style: styles.expiryCard, children: [
|
|
3179
|
+
/* @__PURE__ */ jsxs10("div", { style: styles.expiryRow, children: [
|
|
3180
|
+
/* @__PURE__ */ jsx11("span", { style: styles.expiryLabel, children: "Document type" }),
|
|
3181
|
+
/* @__PURE__ */ jsx11("span", { style: styles.expiryValue, children: verification.documentVerification.documentType || "ID Card" })
|
|
2743
3182
|
] }),
|
|
2744
|
-
verification.documentVerification.issuingCountry && /* @__PURE__ */
|
|
2745
|
-
/* @__PURE__ */
|
|
2746
|
-
/* @__PURE__ */
|
|
3183
|
+
verification.documentVerification.issuingCountry && /* @__PURE__ */ jsxs10("div", { style: styles.expiryRow, children: [
|
|
3184
|
+
/* @__PURE__ */ jsx11("span", { style: styles.expiryLabel, children: "Country" }),
|
|
3185
|
+
/* @__PURE__ */ jsx11("span", { style: styles.expiryValue, children: verification.documentVerification.issuingCountry })
|
|
2747
3186
|
] }),
|
|
2748
|
-
verification.documentVerification.expirationDate && /* @__PURE__ */
|
|
2749
|
-
/* @__PURE__ */
|
|
2750
|
-
/* @__PURE__ */
|
|
3187
|
+
verification.documentVerification.expirationDate && /* @__PURE__ */ jsxs10("div", { style: styles.expiryRow, children: [
|
|
3188
|
+
/* @__PURE__ */ jsx11("span", { style: styles.expiryLabel, children: "Expired on" }),
|
|
3189
|
+
/* @__PURE__ */ jsx11("span", { style: styles.expiryBadge, children: verification.documentVerification.expirationDate })
|
|
2751
3190
|
] })
|
|
2752
3191
|
] }),
|
|
2753
|
-
/* @__PURE__ */
|
|
2754
|
-
/* @__PURE__ */
|
|
2755
|
-
/* @__PURE__ */
|
|
2756
|
-
/* @__PURE__ */
|
|
3192
|
+
/* @__PURE__ */ jsxs10("div", { style: { textAlign: "left" }, children: [
|
|
3193
|
+
/* @__PURE__ */ jsx11(GuidanceTip, { number: 1, text: "Check the expiration date on your document" }),
|
|
3194
|
+
/* @__PURE__ */ jsx11(GuidanceTip, { number: 2, text: "Use a different document that is currently valid" }),
|
|
3195
|
+
/* @__PURE__ */ jsx11(GuidanceTip, { number: 3, text: "Ensure the document details are clearly visible" })
|
|
2757
3196
|
] })
|
|
2758
3197
|
] }),
|
|
2759
|
-
/* @__PURE__ */
|
|
3198
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onRetry, children: "Try with a valid document" }) })
|
|
2760
3199
|
] });
|
|
2761
3200
|
}
|
|
2762
3201
|
function ManualReviewResult({ verification, onDone }) {
|
|
@@ -2764,9 +3203,9 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2764
3203
|
verification.scores?.overall ?? 100 - (verification.riskScore ?? 32)
|
|
2765
3204
|
);
|
|
2766
3205
|
const metrics = computeScoreBreakdown(verification);
|
|
2767
|
-
return /* @__PURE__ */
|
|
2768
|
-
/* @__PURE__ */
|
|
2769
|
-
/* @__PURE__ */
|
|
3206
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3207
|
+
/* @__PURE__ */ jsxs10("div", { style: styles.resultContent, children: [
|
|
3208
|
+
/* @__PURE__ */ jsx11(
|
|
2770
3209
|
"div",
|
|
2771
3210
|
{
|
|
2772
3211
|
style: {
|
|
@@ -2774,7 +3213,7 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2774
3213
|
backgroundColor: `${colors.info}15`,
|
|
2775
3214
|
border: `2px solid ${colors.info}30`
|
|
2776
3215
|
},
|
|
2777
|
-
children: /* @__PURE__ */
|
|
3216
|
+
children: /* @__PURE__ */ jsx11(
|
|
2778
3217
|
"div",
|
|
2779
3218
|
{
|
|
2780
3219
|
style: {
|
|
@@ -2788,9 +3227,9 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2788
3227
|
)
|
|
2789
3228
|
}
|
|
2790
3229
|
),
|
|
2791
|
-
/* @__PURE__ */
|
|
2792
|
-
/* @__PURE__ */
|
|
2793
|
-
/* @__PURE__ */
|
|
3230
|
+
/* @__PURE__ */ jsx11("h1", { style: styles.resultTitle, children: "Under review" }),
|
|
3231
|
+
/* @__PURE__ */ jsx11("p", { style: styles.resultSubtitle, children: "Your verification requires manual review. We'll notify you of the result." }),
|
|
3232
|
+
/* @__PURE__ */ jsx11(
|
|
2794
3233
|
ScoreCard,
|
|
2795
3234
|
{
|
|
2796
3235
|
score,
|
|
@@ -2798,21 +3237,21 @@ function ManualReviewResult({ verification, onDone }) {
|
|
|
2798
3237
|
gradient: `linear-gradient(135deg, ${colors.info}, #0369A1)`
|
|
2799
3238
|
}
|
|
2800
3239
|
),
|
|
2801
|
-
metrics.map((m, i) => /* @__PURE__ */
|
|
3240
|
+
metrics.map((m, i) => /* @__PURE__ */ jsx11(ScoreMetricRow, { ...m }, i))
|
|
2802
3241
|
] }),
|
|
2803
|
-
/* @__PURE__ */
|
|
3242
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onDone, children: "Got it" }) })
|
|
2804
3243
|
] });
|
|
2805
3244
|
}
|
|
2806
3245
|
function GuidanceTip({ number, text }) {
|
|
2807
|
-
return /* @__PURE__ */
|
|
2808
|
-
/* @__PURE__ */
|
|
2809
|
-
/* @__PURE__ */
|
|
3246
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.guidanceTip, children: [
|
|
3247
|
+
/* @__PURE__ */ jsx11("div", { style: styles.guidanceTipNumber, children: number }),
|
|
3248
|
+
/* @__PURE__ */ jsx11("span", { style: styles.guidanceTipText, children: text })
|
|
2810
3249
|
] });
|
|
2811
3250
|
}
|
|
2812
3251
|
function SimplifiedSuccess({ onDone, customMessages }) {
|
|
2813
|
-
return /* @__PURE__ */
|
|
2814
|
-
/* @__PURE__ */
|
|
2815
|
-
/* @__PURE__ */
|
|
3252
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3253
|
+
/* @__PURE__ */ jsxs10("div", { style: { ...styles.resultContent, textAlign: "center" }, children: [
|
|
3254
|
+
/* @__PURE__ */ jsx11(
|
|
2816
3255
|
"div",
|
|
2817
3256
|
{
|
|
2818
3257
|
style: {
|
|
@@ -2821,7 +3260,7 @@ function SimplifiedSuccess({ onDone, customMessages }) {
|
|
|
2821
3260
|
width: 96,
|
|
2822
3261
|
height: 96
|
|
2823
3262
|
},
|
|
2824
|
-
children: /* @__PURE__ */
|
|
3263
|
+
children: /* @__PURE__ */ jsx11(
|
|
2825
3264
|
"div",
|
|
2826
3265
|
{
|
|
2827
3266
|
style: {
|
|
@@ -2838,16 +3277,16 @@ function SimplifiedSuccess({ onDone, customMessages }) {
|
|
|
2838
3277
|
)
|
|
2839
3278
|
}
|
|
2840
3279
|
),
|
|
2841
|
-
/* @__PURE__ */
|
|
2842
|
-
/* @__PURE__ */
|
|
3280
|
+
/* @__PURE__ */ jsx11("h1", { style: { ...styles.resultTitle, fontSize: 24, marginTop: 16 }, children: customMessages?.successTitle || "Verification Successful" }),
|
|
3281
|
+
/* @__PURE__ */ jsx11("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." })
|
|
2843
3282
|
] }),
|
|
2844
|
-
/* @__PURE__ */
|
|
3283
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onDone, children: "Continue" }) })
|
|
2845
3284
|
] });
|
|
2846
3285
|
}
|
|
2847
3286
|
function SimplifiedFailed({ onRetry, customMessages }) {
|
|
2848
|
-
return /* @__PURE__ */
|
|
2849
|
-
/* @__PURE__ */
|
|
2850
|
-
/* @__PURE__ */
|
|
3287
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3288
|
+
/* @__PURE__ */ jsxs10("div", { style: { ...styles.resultContent, textAlign: "center" }, children: [
|
|
3289
|
+
/* @__PURE__ */ jsx11(
|
|
2851
3290
|
"div",
|
|
2852
3291
|
{
|
|
2853
3292
|
style: {
|
|
@@ -2856,7 +3295,7 @@ function SimplifiedFailed({ onRetry, customMessages }) {
|
|
|
2856
3295
|
width: 96,
|
|
2857
3296
|
height: 96
|
|
2858
3297
|
},
|
|
2859
|
-
children: /* @__PURE__ */
|
|
3298
|
+
children: /* @__PURE__ */ jsx11(
|
|
2860
3299
|
"div",
|
|
2861
3300
|
{
|
|
2862
3301
|
style: {
|
|
@@ -2873,16 +3312,16 @@ function SimplifiedFailed({ onRetry, customMessages }) {
|
|
|
2873
3312
|
)
|
|
2874
3313
|
}
|
|
2875
3314
|
),
|
|
2876
|
-
/* @__PURE__ */
|
|
2877
|
-
/* @__PURE__ */
|
|
3315
|
+
/* @__PURE__ */ jsx11("h1", { style: { ...styles.resultTitle, fontSize: 24, marginTop: 16 }, children: customMessages?.failedTitle || "Verification Failed" }),
|
|
3316
|
+
/* @__PURE__ */ jsx11("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." })
|
|
2878
3317
|
] }),
|
|
2879
|
-
/* @__PURE__ */
|
|
3318
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onRetry, children: "Try Again" }) })
|
|
2880
3319
|
] });
|
|
2881
3320
|
}
|
|
2882
3321
|
function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
2883
|
-
return /* @__PURE__ */
|
|
2884
|
-
/* @__PURE__ */
|
|
2885
|
-
/* @__PURE__ */
|
|
3322
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.resultContainer, children: [
|
|
3323
|
+
/* @__PURE__ */ jsxs10("div", { style: { ...styles.resultContent, textAlign: "center" }, children: [
|
|
3324
|
+
/* @__PURE__ */ jsx11(
|
|
2886
3325
|
"div",
|
|
2887
3326
|
{
|
|
2888
3327
|
style: {
|
|
@@ -2891,7 +3330,7 @@ function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
|
2891
3330
|
width: 96,
|
|
2892
3331
|
height: 96
|
|
2893
3332
|
},
|
|
2894
|
-
children: /* @__PURE__ */
|
|
3333
|
+
children: /* @__PURE__ */ jsx11(
|
|
2895
3334
|
"div",
|
|
2896
3335
|
{
|
|
2897
3336
|
style: {
|
|
@@ -2908,9 +3347,9 @@ function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
|
2908
3347
|
)
|
|
2909
3348
|
}
|
|
2910
3349
|
),
|
|
2911
|
-
/* @__PURE__ */
|
|
2912
|
-
/* @__PURE__ */
|
|
2913
|
-
/* @__PURE__ */
|
|
3350
|
+
/* @__PURE__ */ jsx11("h1", { style: { ...styles.resultTitle, fontSize: 24, marginTop: 16 }, children: customMessages?.reviewTitle || "Verification Under Review" }),
|
|
3351
|
+
/* @__PURE__ */ jsx11("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." }),
|
|
3352
|
+
/* @__PURE__ */ jsxs10("div", { style: {
|
|
2914
3353
|
marginTop: 24,
|
|
2915
3354
|
padding: "12px 24px",
|
|
2916
3355
|
backgroundColor: `${colors.info}10`,
|
|
@@ -2918,27 +3357,27 @@ function SimplifiedReview({ verification, onDone, customMessages }) {
|
|
|
2918
3357
|
border: `1px solid ${colors.info}30`,
|
|
2919
3358
|
display: "inline-block"
|
|
2920
3359
|
}, children: [
|
|
2921
|
-
/* @__PURE__ */
|
|
2922
|
-
/* @__PURE__ */
|
|
3360
|
+
/* @__PURE__ */ jsx11("span", { style: { fontSize: 12, color: colors.textSecondary }, children: "Reference: " }),
|
|
3361
|
+
/* @__PURE__ */ jsx11("span", { style: { fontSize: 14, fontWeight: 600, fontFamily: "monospace" }, children: verification.id.slice(0, 8) })
|
|
2923
3362
|
] })
|
|
2924
3363
|
] }),
|
|
2925
|
-
/* @__PURE__ */
|
|
3364
|
+
/* @__PURE__ */ jsx11("div", { style: styles.footer, children: /* @__PURE__ */ jsx11("button", { style: styles.primaryButton, onClick: onDone, children: "Got It" }) })
|
|
2926
3365
|
] });
|
|
2927
3366
|
}
|
|
2928
3367
|
|
|
2929
3368
|
// src/components/ErrorScreen.tsx
|
|
2930
|
-
import { jsx as
|
|
3369
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2931
3370
|
function ErrorScreen({ error, onRetry, onCancel }) {
|
|
2932
|
-
return /* @__PURE__ */
|
|
2933
|
-
/* @__PURE__ */
|
|
2934
|
-
/* @__PURE__ */
|
|
3371
|
+
return /* @__PURE__ */ jsxs11("div", { style: styles.resultContainer, children: [
|
|
3372
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.resultContent, children: [
|
|
3373
|
+
/* @__PURE__ */ jsx12(
|
|
2935
3374
|
"div",
|
|
2936
3375
|
{
|
|
2937
3376
|
style: {
|
|
2938
3377
|
...styles.resultIconOuterRing,
|
|
2939
3378
|
backgroundColor: colors.errorBg
|
|
2940
3379
|
},
|
|
2941
|
-
children: /* @__PURE__ */
|
|
3380
|
+
children: /* @__PURE__ */ jsx12(
|
|
2942
3381
|
"div",
|
|
2943
3382
|
{
|
|
2944
3383
|
style: {
|
|
@@ -2952,26 +3391,26 @@ function ErrorScreen({ error, onRetry, onCancel }) {
|
|
|
2952
3391
|
)
|
|
2953
3392
|
}
|
|
2954
3393
|
),
|
|
2955
|
-
/* @__PURE__ */
|
|
2956
|
-
/* @__PURE__ */
|
|
2957
|
-
error.recoverySuggestion && /* @__PURE__ */
|
|
3394
|
+
/* @__PURE__ */ jsx12("h1", { style: styles.resultTitle, children: "Something went wrong" }),
|
|
3395
|
+
/* @__PURE__ */ jsx12("p", { style: styles.resultSubtitle, children: error.message }),
|
|
3396
|
+
error.recoverySuggestion && /* @__PURE__ */ jsx12("p", { style: { ...styles.bodyText, marginTop: "12px" }, children: error.recoverySuggestion })
|
|
2958
3397
|
] }),
|
|
2959
|
-
/* @__PURE__ */
|
|
2960
|
-
error.isRetryable && /* @__PURE__ */
|
|
2961
|
-
/* @__PURE__ */
|
|
3398
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.footer, children: [
|
|
3399
|
+
error.isRetryable && /* @__PURE__ */ jsx12("button", { style: styles.primaryButton, onClick: onRetry, children: "Try Again" }),
|
|
3400
|
+
/* @__PURE__ */ jsx12("button", { style: styles.textButton, onClick: onCancel, children: "Cancel" })
|
|
2962
3401
|
] })
|
|
2963
3402
|
] });
|
|
2964
3403
|
}
|
|
2965
3404
|
|
|
2966
3405
|
// src/components/LoadingScreen.tsx
|
|
2967
|
-
import { useEffect as
|
|
2968
|
-
import { jsx as
|
|
3406
|
+
import { useEffect as useEffect10 } from "react";
|
|
3407
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2969
3408
|
function LoadingScreen({ message = "Loading..." }) {
|
|
2970
|
-
|
|
3409
|
+
useEffect10(() => {
|
|
2971
3410
|
injectKeyframes();
|
|
2972
3411
|
}, []);
|
|
2973
|
-
return /* @__PURE__ */
|
|
2974
|
-
/* @__PURE__ */
|
|
3412
|
+
return /* @__PURE__ */ jsx13("div", { style: styles.container, children: /* @__PURE__ */ jsxs12("div", { style: styles.loadingContainer, children: [
|
|
3413
|
+
/* @__PURE__ */ jsx13(
|
|
2975
3414
|
"div",
|
|
2976
3415
|
{
|
|
2977
3416
|
style: {
|
|
@@ -2988,18 +3427,19 @@ function LoadingScreen({ message = "Loading..." }) {
|
|
|
2988
3427
|
children: "\u{1F6E1}\uFE0F"
|
|
2989
3428
|
}
|
|
2990
3429
|
),
|
|
2991
|
-
/* @__PURE__ */
|
|
3430
|
+
/* @__PURE__ */ jsx13("p", { style: styles.loadingText, children: message })
|
|
2992
3431
|
] }) });
|
|
2993
3432
|
}
|
|
2994
3433
|
|
|
2995
3434
|
// src/components/VerificationFlow.tsx
|
|
2996
|
-
import { jsx as
|
|
3435
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2997
3436
|
function VerificationFlow({
|
|
2998
3437
|
externalId,
|
|
2999
3438
|
tier = "standard",
|
|
3000
3439
|
documentTypes,
|
|
3001
3440
|
expectedFirstName,
|
|
3002
3441
|
expectedLastName,
|
|
3442
|
+
showVisualGuides = true,
|
|
3003
3443
|
onComplete,
|
|
3004
3444
|
onError,
|
|
3005
3445
|
onCancel,
|
|
@@ -3021,20 +3461,20 @@ function VerificationFlow({
|
|
|
3021
3461
|
retry,
|
|
3022
3462
|
sdk
|
|
3023
3463
|
} = useKoraIDV();
|
|
3024
|
-
const [selectedCountry, setSelectedCountry] =
|
|
3025
|
-
const [flowStep, setFlowStep] =
|
|
3026
|
-
const [showFlipInstruction, setShowFlipInstruction] =
|
|
3027
|
-
const [supportedCountries, setSupportedCountries] =
|
|
3028
|
-
const [countriesLoading, setCountriesLoading] =
|
|
3029
|
-
|
|
3464
|
+
const [selectedCountry, setSelectedCountry] = useState9(null);
|
|
3465
|
+
const [flowStep, setFlowStep] = useState9("consent");
|
|
3466
|
+
const [showFlipInstruction, setShowFlipInstruction] = useState9(true);
|
|
3467
|
+
const [supportedCountries, setSupportedCountries] = useState9([]);
|
|
3468
|
+
const [countriesLoading, setCountriesLoading] = useState9(false);
|
|
3469
|
+
useEffect11(() => {
|
|
3030
3470
|
if (state.step === "document_front") {
|
|
3031
3471
|
setShowFlipInstruction(true);
|
|
3032
3472
|
}
|
|
3033
3473
|
}, [state.step]);
|
|
3034
|
-
|
|
3474
|
+
useEffect11(() => {
|
|
3035
3475
|
startVerification(externalId, tier, expectedFirstName, expectedLastName);
|
|
3036
3476
|
}, [externalId, tier, expectedFirstName, expectedLastName, startVerification]);
|
|
3037
|
-
|
|
3477
|
+
useEffect11(() => {
|
|
3038
3478
|
if (state.error && onError) {
|
|
3039
3479
|
onError(state.error);
|
|
3040
3480
|
}
|
|
@@ -3080,19 +3520,19 @@ function VerificationFlow({
|
|
|
3080
3520
|
...style
|
|
3081
3521
|
};
|
|
3082
3522
|
if (state.error) {
|
|
3083
|
-
return /* @__PURE__ */
|
|
3523
|
+
return /* @__PURE__ */ jsx14("div", { className, style: containerStyle, children: /* @__PURE__ */ jsx14(ErrorScreen, { error: state.error, onRetry: retry, onCancel: handleCancel }) });
|
|
3084
3524
|
}
|
|
3085
3525
|
if (state.isLoading && state.step !== "processing") {
|
|
3086
|
-
return /* @__PURE__ */
|
|
3526
|
+
return /* @__PURE__ */ jsx14("div", { className, style: containerStyle, children: /* @__PURE__ */ jsx14(LoadingScreen, {}) });
|
|
3087
3527
|
}
|
|
3088
3528
|
if (flowStep === "consent" && state.step === "consent") {
|
|
3089
|
-
return /* @__PURE__ */
|
|
3529
|
+
return /* @__PURE__ */ jsx14("div", { className, style: containerStyle, children: /* @__PURE__ */ jsx14(ConsentScreen, { onAccept: handleAcceptConsent, onDecline: handleCancel }) });
|
|
3090
3530
|
}
|
|
3091
3531
|
if (flowStep === "country_selection") {
|
|
3092
3532
|
if (countriesLoading) {
|
|
3093
|
-
return /* @__PURE__ */
|
|
3533
|
+
return /* @__PURE__ */ jsx14("div", { className, style: containerStyle, children: /* @__PURE__ */ jsx14(LoadingScreen, {}) });
|
|
3094
3534
|
}
|
|
3095
|
-
return /* @__PURE__ */
|
|
3535
|
+
return /* @__PURE__ */ jsx14("div", { className, style: containerStyle, children: /* @__PURE__ */ jsx14(
|
|
3096
3536
|
CountrySelectionScreen,
|
|
3097
3537
|
{
|
|
3098
3538
|
countries: supportedCountries,
|
|
@@ -3101,8 +3541,8 @@ function VerificationFlow({
|
|
|
3101
3541
|
}
|
|
3102
3542
|
) });
|
|
3103
3543
|
}
|
|
3104
|
-
return /* @__PURE__ */
|
|
3105
|
-
state.step === "document_selection" && /* @__PURE__ */
|
|
3544
|
+
return /* @__PURE__ */ jsxs13("div", { className, style: containerStyle, children: [
|
|
3545
|
+
state.step === "document_selection" && /* @__PURE__ */ jsx14(
|
|
3106
3546
|
DocumentSelectionScreen,
|
|
3107
3547
|
{
|
|
3108
3548
|
documentTypes,
|
|
@@ -3111,32 +3551,41 @@ function VerificationFlow({
|
|
|
3111
3551
|
onCancel: handleCancel
|
|
3112
3552
|
}
|
|
3113
3553
|
),
|
|
3114
|
-
state.step === "document_front" && /* @__PURE__ */
|
|
3554
|
+
state.step === "document_front" && /* @__PURE__ */ jsx14(
|
|
3115
3555
|
DocumentCaptureScreen,
|
|
3116
3556
|
{
|
|
3117
3557
|
side: "front",
|
|
3118
3558
|
onQualityCheck: (blob) => checkDocumentQuality(blob),
|
|
3119
3559
|
onCapture: (imageData) => uploadDocument(imageData, "front", selectedCountry?.id),
|
|
3120
|
-
onCancel: handleCancel
|
|
3560
|
+
onCancel: handleCancel,
|
|
3561
|
+
showVisualGuides
|
|
3121
3562
|
}
|
|
3122
3563
|
),
|
|
3123
|
-
state.step === "document_back" && showFlipInstruction && /* @__PURE__ */
|
|
3564
|
+
state.step === "document_back" && showFlipInstruction && /* @__PURE__ */ jsx14(
|
|
3124
3565
|
FlipDocumentScreen,
|
|
3125
3566
|
{
|
|
3126
3567
|
onContinue: () => setShowFlipInstruction(false),
|
|
3127
3568
|
onCancel: handleCancel
|
|
3128
3569
|
}
|
|
3129
3570
|
),
|
|
3130
|
-
state.step === "document_back" && !showFlipInstruction && /* @__PURE__ */
|
|
3571
|
+
state.step === "document_back" && !showFlipInstruction && /* @__PURE__ */ jsx14(
|
|
3131
3572
|
DocumentCaptureScreen,
|
|
3132
3573
|
{
|
|
3133
3574
|
side: "back",
|
|
3134
3575
|
onCapture: (imageData) => uploadDocument(imageData, "back", selectedCountry?.id),
|
|
3135
|
-
onCancel: handleCancel
|
|
3576
|
+
onCancel: handleCancel,
|
|
3577
|
+
showVisualGuides
|
|
3136
3578
|
}
|
|
3137
3579
|
),
|
|
3138
|
-
state.step === "selfie" && /* @__PURE__ */
|
|
3139
|
-
|
|
3580
|
+
state.step === "selfie" && /* @__PURE__ */ jsx14(
|
|
3581
|
+
SelfieCaptureScreen,
|
|
3582
|
+
{
|
|
3583
|
+
onCapture: uploadSelfie,
|
|
3584
|
+
onCancel: handleCancel,
|
|
3585
|
+
showVisualGuides
|
|
3586
|
+
}
|
|
3587
|
+
),
|
|
3588
|
+
state.step === "liveness" && /* @__PURE__ */ jsx14(
|
|
3140
3589
|
LivenessScreen,
|
|
3141
3590
|
{
|
|
3142
3591
|
session: state.livenessSession,
|
|
@@ -3145,20 +3594,13 @@ function VerificationFlow({
|
|
|
3145
3594
|
onChallengeComplete: submitChallenge,
|
|
3146
3595
|
onStart: startLiveness,
|
|
3147
3596
|
onComplete: complete,
|
|
3148
|
-
onCancel: handleCancel
|
|
3597
|
+
onCancel: handleCancel,
|
|
3598
|
+
lastChallengeError: state.lastChallengeError,
|
|
3599
|
+
showVisualGuides
|
|
3149
3600
|
}
|
|
3150
3601
|
),
|
|
3151
|
-
state.step === "processing" && /* @__PURE__ */
|
|
3152
|
-
|
|
3153
|
-
{
|
|
3154
|
-
steps: [
|
|
3155
|
-
{ label: "Document analyzed", status: "done" },
|
|
3156
|
-
{ label: "Checking face match", status: "active" },
|
|
3157
|
-
{ label: "Finalizing results", status: "pending" }
|
|
3158
|
-
]
|
|
3159
|
-
}
|
|
3160
|
-
),
|
|
3161
|
-
state.step === "complete" && state.verification && /* @__PURE__ */ jsx13(
|
|
3602
|
+
state.step === "processing" && /* @__PURE__ */ jsx14(ProcessingScreen, {}),
|
|
3603
|
+
state.step === "complete" && state.verification && /* @__PURE__ */ jsx14(
|
|
3162
3604
|
ResultScreen,
|
|
3163
3605
|
{
|
|
3164
3606
|
verification: state.verification,
|
|
@@ -3170,8 +3612,8 @@ function VerificationFlow({
|
|
|
3170
3612
|
}
|
|
3171
3613
|
|
|
3172
3614
|
// src/components/QrHandoffScreen.tsx
|
|
3173
|
-
import { useEffect as
|
|
3174
|
-
import { jsx as
|
|
3615
|
+
import { useEffect as useEffect12, useState as useState10, useRef as useRef7 } from "react";
|
|
3616
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3175
3617
|
function QrHandoffScreen({
|
|
3176
3618
|
session,
|
|
3177
3619
|
onMobileCaptureComplete,
|
|
@@ -3180,11 +3622,11 @@ function QrHandoffScreen({
|
|
|
3180
3622
|
onRefresh,
|
|
3181
3623
|
eventSource
|
|
3182
3624
|
}) {
|
|
3183
|
-
const [timeLeft, setTimeLeft] =
|
|
3184
|
-
const [scanned, setScanned] =
|
|
3185
|
-
const [expired, setExpired] =
|
|
3186
|
-
const timerRef =
|
|
3187
|
-
|
|
3625
|
+
const [timeLeft, setTimeLeft] = useState10(session.expiresIn);
|
|
3626
|
+
const [scanned, setScanned] = useState10(false);
|
|
3627
|
+
const [expired, setExpired] = useState10(false);
|
|
3628
|
+
const timerRef = useRef7();
|
|
3629
|
+
useEffect12(() => {
|
|
3188
3630
|
setTimeLeft(session.expiresIn);
|
|
3189
3631
|
setExpired(false);
|
|
3190
3632
|
setScanned(false);
|
|
@@ -3201,7 +3643,7 @@ function QrHandoffScreen({
|
|
|
3201
3643
|
}, 1e3);
|
|
3202
3644
|
return () => clearInterval(timerRef.current);
|
|
3203
3645
|
}, [session.token]);
|
|
3204
|
-
|
|
3646
|
+
useEffect12(() => {
|
|
3205
3647
|
if (!eventSource) return;
|
|
3206
3648
|
const handleStatus = (event) => {
|
|
3207
3649
|
try {
|
|
@@ -3227,34 +3669,34 @@ function QrHandoffScreen({
|
|
|
3227
3669
|
const seconds = timeLeft % 60;
|
|
3228
3670
|
const qrSize = 200;
|
|
3229
3671
|
if (expired) {
|
|
3230
|
-
return /* @__PURE__ */
|
|
3231
|
-
/* @__PURE__ */
|
|
3232
|
-
/* @__PURE__ */
|
|
3233
|
-
/* @__PURE__ */
|
|
3234
|
-
/* @__PURE__ */
|
|
3235
|
-
/* @__PURE__ */
|
|
3672
|
+
return /* @__PURE__ */ jsx15("div", { style: qrStyles.container, children: /* @__PURE__ */ jsxs14("div", { style: qrStyles.content, children: [
|
|
3673
|
+
/* @__PURE__ */ jsx15("div", { style: qrStyles.expiredIcon, children: "\u23F1" }),
|
|
3674
|
+
/* @__PURE__ */ jsx15("h2", { style: qrStyles.title, children: "QR Code Expired" }),
|
|
3675
|
+
/* @__PURE__ */ jsx15("p", { style: qrStyles.subtitle, children: "The QR code has expired. Generate a new one to continue." }),
|
|
3676
|
+
/* @__PURE__ */ jsx15("button", { style: qrStyles.primaryButton, onClick: onRefresh, children: "Generate New QR Code" }),
|
|
3677
|
+
/* @__PURE__ */ jsx15("button", { style: qrStyles.secondaryButton, onClick: onContinueOnDevice, children: "Continue on this device instead" })
|
|
3236
3678
|
] }) });
|
|
3237
3679
|
}
|
|
3238
3680
|
if (scanned) {
|
|
3239
|
-
return /* @__PURE__ */
|
|
3240
|
-
/* @__PURE__ */
|
|
3241
|
-
/* @__PURE__ */
|
|
3242
|
-
/* @__PURE__ */
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
/* @__PURE__ */
|
|
3681
|
+
return /* @__PURE__ */ jsx15("div", { style: qrStyles.container, children: /* @__PURE__ */ jsxs14("div", { style: qrStyles.content, children: [
|
|
3682
|
+
/* @__PURE__ */ jsx15("div", { style: qrStyles.spinnerContainer, children: /* @__PURE__ */ jsx15("div", { style: qrStyles.spinner }) }),
|
|
3683
|
+
/* @__PURE__ */ jsx15("h2", { style: qrStyles.title, children: "Capturing on your phone..." }),
|
|
3684
|
+
/* @__PURE__ */ jsx15("p", { style: qrStyles.subtitle, children: "Complete the document scan and selfie on your mobile device. This page will update automatically when done." }),
|
|
3685
|
+
/* @__PURE__ */ jsxs14("div", { style: qrStyles.statusBadge, children: [
|
|
3686
|
+
/* @__PURE__ */ jsx15("span", { style: qrStyles.statusDot }),
|
|
3245
3687
|
"Connected \u2014 waiting for capture"
|
|
3246
3688
|
] })
|
|
3247
3689
|
] }) });
|
|
3248
3690
|
}
|
|
3249
|
-
return /* @__PURE__ */
|
|
3250
|
-
/* @__PURE__ */
|
|
3251
|
-
/* @__PURE__ */
|
|
3252
|
-
/* @__PURE__ */
|
|
3253
|
-
/* @__PURE__ */
|
|
3691
|
+
return /* @__PURE__ */ jsx15("div", { style: qrStyles.container, children: /* @__PURE__ */ jsxs14("div", { style: qrStyles.content, children: [
|
|
3692
|
+
/* @__PURE__ */ jsx15("h2", { style: qrStyles.title, children: "Scan with your phone" }),
|
|
3693
|
+
/* @__PURE__ */ jsx15("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." }),
|
|
3694
|
+
/* @__PURE__ */ jsxs14("div", { style: qrStyles.qrContainer, children: [
|
|
3695
|
+
/* @__PURE__ */ jsx15("div", { style: {
|
|
3254
3696
|
...qrStyles.qrBox,
|
|
3255
3697
|
width: qrSize,
|
|
3256
3698
|
height: qrSize
|
|
3257
|
-
}, children: /* @__PURE__ */
|
|
3699
|
+
}, children: /* @__PURE__ */ jsx15(
|
|
3258
3700
|
"img",
|
|
3259
3701
|
{
|
|
3260
3702
|
src: `https://api.qrserver.com/v1/create-qr-code/?size=${qrSize}x${qrSize}&data=${encodeURIComponent(session.captureUrl)}&margin=8`,
|
|
@@ -3264,26 +3706,26 @@ function QrHandoffScreen({
|
|
|
3264
3706
|
style: { borderRadius: 12 }
|
|
3265
3707
|
}
|
|
3266
3708
|
) }),
|
|
3267
|
-
/* @__PURE__ */
|
|
3709
|
+
/* @__PURE__ */ jsxs14("div", { style: qrStyles.timer, children: [
|
|
3268
3710
|
minutes,
|
|
3269
3711
|
":",
|
|
3270
3712
|
seconds.toString().padStart(2, "0"),
|
|
3271
3713
|
" remaining"
|
|
3272
3714
|
] })
|
|
3273
3715
|
] }),
|
|
3274
|
-
/* @__PURE__ */
|
|
3275
|
-
/* @__PURE__ */
|
|
3276
|
-
/* @__PURE__ */
|
|
3277
|
-
/* @__PURE__ */
|
|
3716
|
+
/* @__PURE__ */ jsxs14("div", { style: qrStyles.steps, children: [
|
|
3717
|
+
/* @__PURE__ */ jsx15(Step, { number: 1, text: "Open your phone's camera" }),
|
|
3718
|
+
/* @__PURE__ */ jsx15(Step, { number: 2, text: "Point at the QR code" }),
|
|
3719
|
+
/* @__PURE__ */ jsx15(Step, { number: 3, text: "Complete the capture on your phone" })
|
|
3278
3720
|
] }),
|
|
3279
|
-
/* @__PURE__ */
|
|
3280
|
-
/* @__PURE__ */
|
|
3721
|
+
/* @__PURE__ */ jsx15("div", { style: qrStyles.divider, children: /* @__PURE__ */ jsx15("span", { style: qrStyles.dividerText, children: "or" }) }),
|
|
3722
|
+
/* @__PURE__ */ jsx15("button", { style: qrStyles.secondaryButton, onClick: onContinueOnDevice, children: "Continue on this device" })
|
|
3281
3723
|
] }) });
|
|
3282
3724
|
}
|
|
3283
3725
|
function Step({ number, text }) {
|
|
3284
|
-
return /* @__PURE__ */
|
|
3285
|
-
/* @__PURE__ */
|
|
3286
|
-
/* @__PURE__ */
|
|
3726
|
+
return /* @__PURE__ */ jsxs14("div", { style: qrStyles.step, children: [
|
|
3727
|
+
/* @__PURE__ */ jsx15("div", { style: qrStyles.stepNumber, children: number }),
|
|
3728
|
+
/* @__PURE__ */ jsx15("span", { style: qrStyles.stepText, children: text })
|
|
3287
3729
|
] });
|
|
3288
3730
|
}
|
|
3289
3731
|
var qrStyles = {
|