UNPKG

dikript-react-identity-comparison-sdk

Version:

A Dikript's React SDK for identity comparison and liveness checks.

785 lines (764 loc) 38.7 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('face-api.js')) : typeof define === 'function' && define.amd ? define(['exports', 'react', 'face-api.js'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.reactIdentityComparisonSdk = {}, global.React, global.faceapi)); })(this, (function (exports, React, faceapi) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var faceapi__namespace = /*#__PURE__*/_interopNamespace(faceapi); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var LIVENESS_ENDPOINT = '/livelinesscheck'; var IDENTITY_COMPARISON_ENDPOINT = '/identitycomparison'; var DEFAULT_TIMEOUT = 30000; // 30 seconds default timeout /** * Helper function to add timeout to fetch requests * @param {Promise<Response>} fetchPromise - The fetch promise * @param {number} timeout - Timeout in milliseconds * @returns {Promise<Response>} - Promise that will reject if timeout is exceeded */ function timeoutFetch(fetchPromise, timeout) { if (timeout === void 0) { timeout = DEFAULT_TIMEOUT; } var timeoutId; var timeoutPromise = new Promise(function (_, reject) { timeoutId = setTimeout(function () { reject(new Error("Request timed out after ".concat(timeout, "ms"))); }, timeout); }); return Promise.race([fetchPromise, timeoutPromise]).then(function (response) { clearTimeout(timeoutId); return response; })["catch"](function (error) { clearTimeout(timeoutId); throw error; }); } /** * Send an image for liveness check * @param {string} dataUrl - Base64 encoded image data URL * @param {string} apiKey - API key for authentication * @param {string} apiUrl - Base URL for API requests * @param {number} timeout - Timeout in milliseconds (optional) * @returns {Promise<LivenessResponse>} - Response from the liveness check API */ function sendImageForLiveness(apiUrl, apiKey, dataUrl, timeout) { var _a; if (timeout === void 0) { timeout = DEFAULT_TIMEOUT; } return __awaiter(this, void 0, void 0, function () { var base64String, formData, fetchPromise, response, errorText, result, formattedResponse, error_1; return __generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 5,, 6]); base64String = dataUrl.split(',')[1]; formData = new FormData(); formData.append('ImageBase64String', base64String); console.log('Sending liveness check to:', "".concat(apiUrl).concat(LIVENESS_ENDPOINT)); fetchPromise = fetch("".concat(apiUrl).concat(LIVENESS_ENDPOINT), { method: 'POST', headers: { 'x-api-key': apiKey }, body: formData }); return [4 /*yield*/, timeoutFetch(fetchPromise, timeout)]; case 1: response = _b.sent(); if (!!response.ok) return [3 /*break*/, 3]; return [4 /*yield*/, response.text()]; case 2: errorText = _b.sent(); console.error('Liveness check failed with status:', response.status, errorText); throw new Error("Server error: ".concat(response.status, " - ").concat(errorText)); case 3: return [4 /*yield*/, response.json()]; case 4: result = _b.sent(); // Check if the API returned isLively property if (result.data && typeof result.data.isLively !== 'undefined') { formattedResponse = { isLive: result.data.isLively, confidence: ((_a = result.data.liveness) === null || _a === void 0 ? void 0 : _a.livenessProbability) || 0, message: result.data.isLively ? 'Liveness check passed' : 'Liveness check failed' }; return [2 /*return*/, formattedResponse]; } else { return [2 /*return*/, { isLive: result.isLively || false, confidence: result.confidence || 0, message: result.message || '' }]; } case 5: error_1 = _b.sent(); console.error('Error in sendImageForLiveness:', error_1); throw error_1; case 6: return [2 /*return*/]; } }); }); } /** * Send an image for identity comparison * @param {string} dataUrl - Base64 encoded image data URL * @param {string} idType - Type of ID (e.g., BVN, NIN) * @param {string} idNumber - ID number * @param {string} apiKey - API key for authentication * @param {string} apiUrl - Base URL for API requests * @param {number} timeout - Timeout in milliseconds (optional) * @returns {Promise<IdentityComparisonResponse>} - Response from the identity comparison API */ function sendImageForIdentityComparison(apiUrl, apiKey, dataUrl, idType, idNumber, timeout) { if (timeout === void 0) { timeout = DEFAULT_TIMEOUT; } return __awaiter(this, void 0, void 0, function () { var base64String, formData, fetchPromise, response, errorText, result, formattedResponse, error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 5,, 6]); base64String = dataUrl.split(',')[1]; formData = new FormData(); formData.append('ImageBase64String', base64String); formData.append('idType', idType); formData.append('idNumber', idNumber); console.log('Sending identity comparison to:', "".concat(apiUrl).concat(IDENTITY_COMPARISON_ENDPOINT)); console.log('ID Type:', idType); console.log('ID Number:', idNumber); fetchPromise = fetch("".concat(apiUrl).concat(IDENTITY_COMPARISON_ENDPOINT), { method: 'POST', headers: { 'x-api-key': apiKey }, body: formData }); return [4 /*yield*/, timeoutFetch(fetchPromise, timeout)]; case 1: response = _a.sent(); if (!!response.ok) return [3 /*break*/, 3]; return [4 /*yield*/, response.text()]; case 2: errorText = _a.sent(); console.error('Identity comparison failed with status:', response.status, errorText); throw new Error("Server error: ".concat(response.status, " - ").concat(errorText)); case 3: return [4 /*yield*/, response.json()]; case 4: result = _a.sent(); console.log('Identity comparison raw result:', JSON.stringify(result)); // Check if the API returned data in the expected structure if (result.data && typeof result.data.isMatch !== 'undefined') { console.log('Found isMatch in result.data:', result.data.isMatch); formattedResponse = { isMatch: result.data.isMatch, confidence: result.data.confidence || 0, message: result.data.isMatch ? 'Identity matched successfully' : 'Identity did not match', matchDetails: result.data.detail || {} }; console.log('Formatted identity comparison response:', formattedResponse); return [2 /*return*/, formattedResponse]; } else { console.log('Using fallback response format'); return [2 /*return*/, { isMatch: result.isMatch || false, confidence: result.confidence || 0, message: result.message || '' }]; } case 5: error_2 = _a.sent(); console.error('Error in sendImageForIdentityComparison:', error_2); throw error_2; case 6: return [2 /*return*/]; } }); }); } function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = "@import url(\"https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap\");.dikriptLivenessPopup{align-items:center;background-color:rgba(0,0,0,.5);box-sizing:border-box;display:flex;font-family:Poppins,sans-serif;height:100%;justify-content:center;left:0;overflow-y:auto;padding:20px;position:fixed;top:0;width:100%;z-index:1000}.dikriptPopupContent{background-color:#fff;border-radius:10px;box-shadow:0 4px 6px rgba(0,0,0,.1);color:#333;max-width:500px;padding:20px;text-align:left;width:100%}.dikriptHeader{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.dikriptBackButton,.dikriptCloseButton{background:none;border:none;color:#333;cursor:pointer;display:block;font-size:30px;opacity:1;padding:8px;position:relative;visibility:visible;z-index:10}.dikriptLogo{height:30px;max-width:100px}.dikriptHeaderCenter{flex:1;text-align:center}.dikriptLogoText{font-size:18px;font-weight:700}.dikriptPopupContent h2{color:#0b2d61;font-size:28px;font-weight:700;margin-bottom:20px}.dikriptSubtitle{color:#555;font-size:18px;font-weight:600}.dikriptPermissions{margin-bottom:20px}.dikriptPermissionGroup h3{color:#0b2d61;font-size:20px;font-weight:600;margin-bottom:10px}.dikriptPermissionGroup ul{list-style-type:none;padding-left:0}.dikriptPermissionGroup li{align-items:center;display:flex;font-size:16px;margin-bottom:8px}.dikriptPermissionGroup li:before{color:#0b2d61;content:\"✓\";font-weight:700;margin-right:10px}.dikriptCameraContainer{border-radius:10px;box-shadow:0 2px 4px rgba(0,0,0,.1);margin:0 auto 20px;max-width:400px;overflow:hidden;position:relative;width:100%}.dikriptCameraContainer video{display:block;width:100%}.dikriptFaceOverlay{height:100%;left:0;position:absolute;top:0;width:100%}.dikriptMessage{color:#0b2d61;font-weight:600;margin:15px 0;text-align:center}.dikriptMessage.dikriptError{color:#dc3545}.dikriptMessage.dikriptSuccess{color:#0b2d61}.dikriptConsent{margin-bottom:20px}.dikriptConsent label{align-items:center;color:#1c1a1a;display:flex;font-size:14px}.dikriptConsent input[type=checkbox]{margin-right:10px}.dikriptButtonContainer{display:flex;flex-direction:column;gap:10px}.dikriptActionButton,.dikriptCaptureButton,.dikriptRetryButton{background-color:#0b2d61;border:none;border-radius:5px;color:#fff;cursor:pointer;font-size:16px;font-weight:600;padding:12px 20px;transition:background-color .3s ease}.dikriptActionButton:hover,.dikriptCaptureButton:hover,.dikriptRetryButton:hover{background-color:#0052cc}.dikriptActionButton:disabled{background-color:#ccc;cursor:not-allowed}.dikriptConsentConfirmation,.dikriptSuccessMessage{color:#1c1a1a;font-size:18px;font-weight:600;margin-bottom:20px;text-align:center}.dikriptActionButton{margin:10px auto;max-width:200px;width:100%}.dikriptCloseButtonStyled,.dikriptFooter{margin-top:20px}.dikriptFooter{border-top:1px solid #eee;color:#777;font-size:14px;padding-top:10px;text-align:center}.dikriptCenterContent{align-items:center;display:flex;flex-direction:column;justify-content:center;text-align:center}.dikriptIdSelection{display:flex;flex-direction:column;gap:10px;margin-bottom:20px}.dikriptIdNumberInput,.dikriptIdTypeSelect{border:1px solid #ccc;border-radius:5px;font-size:16px;padding:10px}@media (max-width:600px){.dikriptPopupContent{padding:15px}.dikriptPopupContent h2{font-size:20px}.dikriptConsent label,.dikriptPermissionGroup li,.dikriptSubtitle{font-size:14px}.dikriptActionButton,.dikriptCaptureButton{font-size:14px;padding:10px}}.dikriptLoadingOverlay{align-items:center;background-color:hsla(0,0%,100%,.7);border-radius:12px;bottom:0;display:flex;flex-direction:column;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:10}.dikriptLoader{animation:dikriptSpin 1s linear infinite;border:5px solid #f3f3f3;border-radius:50%;border-top-color:#06c;height:50px;margin-bottom:16px;width:50px}@keyframes dikriptSpin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}"; styleInject(css_248z,{"insertAt":"top"}); // Default ID types var DEFAULT_ID_TYPES = [{ value: 'BVN', label: 'BVN' }, { value: 'PHONENUMBER', label: 'Phone Number' }, { value: 'FRSC', label: 'FRSC' }, { value: 'NIN', label: 'NIN' }]; /** * Identity Comparison Popup Component * * A React component that provides a UI for identity verification using liveness checks * and ID verification. */ var IdentityComparisonPopup = function IdentityComparisonPopup(_a) { var apiKey = _a.apiKey, name = _a.name, apiUrl = _a.apiUrl, onClose = _a.onClose, onIdentityComparisonResult = _a.onIdentityComparisonResult, modelPath = _a.modelPath, _b = _a.idTypes, idTypes = _b === void 0 ? DEFAULT_ID_TYPES : _b; // State management var _c = React.useState(1), currentStep = _c[0], setCurrentStep = _c[1]; var _d = React.useState(false), consentGiven = _d[0], setConsentGiven = _d[1]; var _e = React.useState(''), selectedIdType = _e[0], setSelectedIdType = _e[1]; var _f = React.useState(''), idNumber = _f[0], setIdNumber = _f[1]; var _g = React.useState(false), showCamera = _g[0], setShowCamera = _g[1]; var _h = React.useState(''), message = _h[0], setMessage = _h[1]; var _j = React.useState(false), isError = _j[0], setIsError = _j[1]; var _k = React.useState(false), isSuccess = _k[0], setIsSuccess = _k[1]; var _l = React.useState(false), faceDetected = _l[0], setFaceDetected = _l[1]; var _m = React.useState(false), processing = _m[0], setProcessing = _m[1]; var _o = React.useState(false), identityProcessing = _o[0], setIdentityProcessing = _o[1]; var _p = React.useState(false), showRetry = _p[0], setShowRetry = _p[1]; var _q = React.useState(null), identityComparisonResult = _q[0], setIdentityComparisonResult = _q[1]; var _r = React.useState(false), modelsLoaded = _r[0], setModelsLoaded = _r[1]; // Refs var videoRef = React.useRef(null); var canvasRef = React.useRef(null); var streamRef = React.useRef(null); var detectionIntervalRef = React.useRef(null); // Load face-api.js models React.useEffect(function () { var loadModels = function loadModels() { return __awaiter(void 0, void 0, void 0, function () { var error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2,, 3]); console.log('Loading face-api.js models from:', modelPath); return [4 /*yield*/, Promise.all([faceapi__namespace.nets.tinyFaceDetector.loadFromUri(modelPath), faceapi__namespace.nets.faceLandmark68Net.loadFromUri(modelPath)])]; case 1: _a.sent(); console.log('Face-api.js models loaded successfully'); setModelsLoaded(true); return [3 /*break*/, 3]; case 2: error_1 = _a.sent(); console.error('Error loading face-api.js models:', error_1); setMessage('Error loading face detection models. Please check console for details.'); setIsError(true); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; loadModels(); // Cleanup function return function () { if (streamRef.current) { streamRef.current.getTracks().forEach(function (track) { return track.stop(); }); } if (detectionIntervalRef.current) { window.clearInterval(detectionIntervalRef.current); } }; }, [modelPath]); // Setup camera and face detection var _setupCamera = function setupCamera() { return __awaiter(void 0, void 0, void 0, function () { var stream, error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2,, 3]); if (!videoRef.current) { console.error('Video ref not available'); setTimeout(function () { if (videoRef.current) { _setupCamera(); } }, 500); return [2 /*return*/]; } console.log('Requesting camera access...'); return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ video: true, audio: false })]; case 1: stream = _a.sent(); console.log('Camera access granted'); videoRef.current.srcObject = stream; streamRef.current = stream; videoRef.current.onloadedmetadata = function () { if (videoRef.current) { videoRef.current.play().then(function () { console.log('Video playback started'); _startFaceDetection(); })["catch"](function (err) { console.error('Error playing video:', err); }); } }; setMessage('Position your face in the frame'); return [3 /*break*/, 3]; case 2: error_2 = _a.sent(); console.error('Error accessing camera:', error_2); setMessage('Unable to access the camera. Please ensure you have given permission.'); setIsError(true); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; // Start face detection interval var _startFaceDetection = function startFaceDetection() { if (!videoRef.current || !canvasRef.current) { console.error('Video or canvas ref not available'); return; } if (videoRef.current.readyState !== 4) { console.log('Video not ready yet, waiting...'); setTimeout(_startFaceDetection, 100); return; } console.log('Starting face detection'); var canvas = canvasRef.current; var video = videoRef.current; canvas.width = video.videoWidth; canvas.height = video.videoHeight; var displaySize = { width: video.videoWidth, height: video.videoHeight }; faceapi__namespace.matchDimensions(canvas, displaySize); detectionIntervalRef.current = window.setInterval(function () { return __awaiter(void 0, void 0, void 0, function () { var detections, ctx, resizedDetections, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!videoRef.current) return [2 /*return*/]; _a.label = 1; case 1: _a.trys.push([1, 3,, 4]); return [4 /*yield*/, faceapi__namespace.detectAllFaces(videoRef.current, new faceapi__namespace.TinyFaceDetectorOptions()).withFaceLandmarks()]; case 2: detections = _a.sent(); ctx = canvas.getContext('2d'); if (!ctx) return [2 /*return*/]; ctx.clearRect(0, 0, canvas.width, canvas.height); if (detections.length > 0) { resizedDetections = faceapi__namespace.resizeResults(detections, displaySize); faceapi__namespace.draw.drawDetections(canvas, resizedDetections); faceapi__namespace.draw.drawFaceLandmarks(canvas, resizedDetections); setFaceDetected(true); setMessage('Face detected. Click "Capture Photo" when ready.'); } else { setFaceDetected(false); setMessage('No face detected. Please position your face in the frame.'); } return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); console.error('Error in face detection:', err_1); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }, 100); }; // Navigate to next step var nextStep = function nextStep() { if (currentStep === 1 && !consentGiven) { return; } if (currentStep === 2 && (!selectedIdType || !idNumber)) { return; } setIsError(false); setMessage(''); if (currentStep === 2) { setShowCamera(false); // Don't show camera immediately, show the start camera button first } setCurrentStep(currentStep + 1); }; // Go back to previous step var goBack = function goBack() { setIsError(false); setMessage(''); if (currentStep === 3) { setShowCamera(false); if (streamRef.current) { streamRef.current.getTracks().forEach(function (track) { return track.stop(); }); } if (detectionIntervalRef.current) { window.clearInterval(detectionIntervalRef.current); } } setCurrentStep(currentStep - 1); }; // Close the popup var closePopup = function closePopup() { // Stop camera if active if (streamRef.current) { streamRef.current.getTracks().forEach(function (track) { return track.stop(); }); } // Clear any intervals if (detectionIntervalRef.current) { window.clearInterval(detectionIntervalRef.current); } onClose(); }; // Start camera var startCamera = function startCamera() { if (!modelsLoaded) { setMessage('Face detection models are still loading. Please wait...'); return; } setShowCamera(true); _setupCamera(); }; // Capture photo for liveness check var capturePhoto = function capturePhoto() { return __awaiter(void 0, void 0, void 0, function () { var canvas, ctx, photoData, livenessResponse, identityResponse, identityError_1, error_3; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!videoRef.current || !faceDetected) { setMessage('No face detected. Please position your face in the frame.'); setIsError(true); return [2 /*return*/]; } clearInterval(detectionIntervalRef.current); setProcessing(true); setMessage('Processing image...'); _a.label = 1; case 1: _a.trys.push([1, 10,, 11]); canvas = document.createElement('canvas'); canvas.width = videoRef.current.videoWidth; canvas.height = videoRef.current.videoHeight; ctx = canvas.getContext('2d'); if (!ctx) return [3 /*break*/, 9]; ctx.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height); photoData = canvas.toDataURL('image/png'); // Send for liveness check setMessage('Performing liveness check...'); return [4 /*yield*/, sendImageForLiveness(apiUrl, apiKey, photoData)]; case 2: livenessResponse = _a.sent(); if (!livenessResponse.isLive) return [3 /*break*/, 8]; setMessage('Liveness check successful. Proceeding with identity comparison...'); setIdentityProcessing(true); _a.label = 3; case 3: _a.trys.push([3, 5, 6, 7]); return [4 /*yield*/, sendImageForIdentityComparison(apiUrl, apiKey, photoData, selectedIdType, idNumber)]; case 4: identityResponse = _a.sent(); setIdentityComparisonResult(identityResponse); setIsSuccess(true); setCurrentStep(4); // Move to results step onIdentityComparisonResult(identityResponse); return [3 /*break*/, 7]; case 5: identityError_1 = _a.sent(); console.error('Error during identity comparison:', identityError_1); setMessage(identityError_1.message || 'Failed to complete identity comparison. Please try again.'); setIsError(true); setShowRetry(true); return [3 /*break*/, 7]; case 6: setIdentityProcessing(false); setProcessing(false); return [7 /*endfinally*/]; case 7: return [3 /*break*/, 9]; case 8: // Handle failed liveness check with a specific message console.log('Liveness check failed with message:', livenessResponse.message); setMessage(livenessResponse.message || 'Liveness check failed. Please try again with better lighting and ensure your face is clearly visible.'); setIsError(true); setShowRetry(true); setProcessing(false); _a.label = 9; case 9: return [3 /*break*/, 11]; case 10: error_3 = _a.sent(); console.error('Error during verification:', error_3); setMessage(error_3.message || 'Failed to process the image. Please try again.'); setIsError(true); setShowRetry(true); setProcessing(false); setIdentityProcessing(false); return [3 /*break*/, 11]; case 11: return [2 /*return*/]; } }); }); }; // Retry the verification process var retryCapture = function retryCapture() { setShowRetry(false); setShowCamera(true); setFaceDetected(false); setMessage(''); setIsError(false); startCamera(); }; return /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptLivenessPopup" }, /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptPopupContent" }, /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptHeader" }, currentStep > 1 && /*#__PURE__*/React__default["default"].createElement("button", { className: "dikriptBackButton", onClick: goBack }, "\u2190"), /*#__PURE__*/React__default["default"].createElement("img", { src: "https://api.dikript.com/dikript-logo.png", alt: "Dikript logo", className: "dikriptLogo" }), /*#__PURE__*/React__default["default"].createElement("button", { className: "dikriptCloseButton", onClick: closePopup }, "\xD7")), /*#__PURE__*/React__default["default"].createElement("h2", null, "Identity Verification"), currentStep === 1 ? (/*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement("p", { className: "dikriptSubtitle" }, name, " will access the following information:"), /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptPermissions" }, /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptPermissionGroup" }, /*#__PURE__*/React__default["default"].createElement("h3", null, name, " will be able to"), /*#__PURE__*/React__default["default"].createElement("ul", null, /*#__PURE__*/React__default["default"].createElement("li", null, "Access your camera"), /*#__PURE__*/React__default["default"].createElement("li", null, "Capture your photo"), /*#__PURE__*/React__default["default"].createElement("li", null, "Perform identity verification"))), /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptPermissionGroup" }, /*#__PURE__*/React__default["default"].createElement("h3", null, name, " will not be able to"), /*#__PURE__*/React__default["default"].createElement("ul", null, /*#__PURE__*/React__default["default"].createElement("li", null, "Store your photo permanently"), /*#__PURE__*/React__default["default"].createElement("li", null, "Access your other personal data"), /*#__PURE__*/React__default["default"].createElement("li", null, "Share your information with third parties")))), /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptConsent" }, /*#__PURE__*/React__default["default"].createElement("label", null, /*#__PURE__*/React__default["default"].createElement("input", { type: "checkbox", checked: consentGiven, onChange: function onChange() { return setConsentGiven(!consentGiven); } }), "I consent to the processing of my biometric data for identity verification purposes.")), /*#__PURE__*/React__default["default"].createElement("button", { onClick: nextStep, disabled: !consentGiven, className: "dikriptActionButton" }, "Continue"))) : currentStep === 2 ? (/*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement("p", { className: "dikriptSubtitle" }, "Select an ID type and enter your ID number:"), /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptIdSelection" }, /*#__PURE__*/React__default["default"].createElement("select", { value: selectedIdType, onChange: function onChange(e) { return setSelectedIdType(e.target.value); }, className: "dikriptIdTypeSelect" }, /*#__PURE__*/React__default["default"].createElement("option", { value: "" }, "Select ID Type"), idTypes.map(function (idType) { return /*#__PURE__*/React__default["default"].createElement("option", { key: idType.value, value: idType.value }, idType.label); })), /*#__PURE__*/React__default["default"].createElement("input", { type: "text", value: idNumber, onChange: function onChange(e) { return setIdNumber(e.target.value); }, placeholder: "Enter ID Number", className: "dikriptIdNumberInput" })), /*#__PURE__*/React__default["default"].createElement("button", { onClick: nextStep, disabled: !selectedIdType || !idNumber, className: "dikriptActionButton" }, "Continue"))) : currentStep === 3 && !showCamera ? (/*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptCenterContent" }, /*#__PURE__*/React__default["default"].createElement("p", { className: "dikriptConsentConfirmation" }, "Proceed to liveness check"), /*#__PURE__*/React__default["default"].createElement("button", { onClick: startCamera, className: "dikriptActionButton" }, "Start Camera"))) : showCamera ? (/*#__PURE__*/React__default["default"].createElement("div", { style: { position: 'relative' } }, /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptCameraContainer" }, /*#__PURE__*/React__default["default"].createElement("video", { ref: videoRef, autoPlay: true, playsInline: true, muted: true }), /*#__PURE__*/React__default["default"].createElement("canvas", { ref: canvasRef, className: "dikriptFaceOverlay" })), /*#__PURE__*/React__default["default"].createElement("p", { className: "dikriptMessage ".concat(isError ? 'dikriptError' : '', " ").concat(isSuccess ? 'dikriptSuccess' : '') }, message), /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptButtonContainer" }, faceDetected && !processing && !identityProcessing && (/*#__PURE__*/React__default["default"].createElement("button", { onClick: capturePhoto, className: "dikriptCaptureButton" }, "Capture Photo")), showRetry && !identityProcessing && (/*#__PURE__*/React__default["default"].createElement("button", { onClick: retryCapture, className: "dikriptRetryButton" }, "Retry"))), identityProcessing && (/*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptLoadingOverlay" }, /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptLoader" }), /*#__PURE__*/React__default["default"].createElement("p", null, "Processing identity verification..."), /*#__PURE__*/React__default["default"].createElement("p", null, "This might take a few moments"))))) : currentStep === 4 ? (/*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptCenterContent" }, /*#__PURE__*/React__default["default"].createElement("p", { className: "dikriptSuccessMessage" }, "Identity comparison completed."), identityComparisonResult && (/*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement("p", null, "Match: ", identityComparisonResult.isMatch ? 'Yes' : 'No'), /*#__PURE__*/React__default["default"].createElement("p", null, "Confidence: ", (identityComparisonResult.confidence * 100).toFixed(2), "%"))), /*#__PURE__*/React__default["default"].createElement("button", { onClick: closePopup, className: "dikriptActionButton" }, "Close"))) : null, /*#__PURE__*/React__default["default"].createElement("div", { className: "dikriptFooter" }, "Powered by Dikript"))); }; exports.IdentityComparisonPopup = IdentityComparisonPopup; exports["default"] = IdentityComparisonPopup; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=index.js.map