pipwave-ekyc-uikit 3.0.2 → 3.0.3

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/pw-bundle.js CHANGED
@@ -3923,7 +3923,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
3923
3923
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
3924
3924
 
3925
3925
  "use strict";
3926
- eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nconst getGoogleIcon_1 = __webpack_require__(/*! ../helper/getGoogleIcon */ \"./src/helper/getGoogleIcon.ts\");\nconst stepper_1 = __webpack_require__(/*! ../helper/stepper */ \"./src/helper/stepper.ts\");\nconst uisdk_1 = __webpack_require__(/*! ../uisdk */ \"./src/uisdk.ts\");\nconst verification_1 = __webpack_require__(/*! ../constant/verification */ \"./src/constant/verification.ts\");\nconst footer_1 = __importDefault(__webpack_require__(/*! ../components/footer */ \"./src/components/footer.ts\"));\nconst MainPage_1 = __importDefault(__webpack_require__(/*! ../classes/MainPage */ \"./src/classes/MainPage.ts\"));\nconst StartSelfie_1 = __importDefault(__webpack_require__(/*! ./StartSelfie */ \"./src/pageClass/StartSelfie.ts\"));\nconst stepper_2 = __importDefault(__webpack_require__(/*! ../components/stepper */ \"./src/components/stepper.ts\"));\nconst merchantLogo_1 = __importDefault(__webpack_require__(/*! ../components/merchantLogo */ \"./src/components/merchantLogo.ts\"));\nconst VerifyCc_1 = __importDefault(__webpack_require__(/*! ./VerifyCc */ \"./src/pageClass/VerifyCc.ts\"));\nconst VerifyId_1 = __importDefault(__webpack_require__(/*! ./VerifyId */ \"./src/pageClass/VerifyId.ts\"));\nconst VerifyPoa_1 = __importDefault(__webpack_require__(/*! ./VerifyPoa */ \"./src/pageClass/VerifyPoa.ts\"));\nconst CompletedPage_1 = __importDefault(__webpack_require__(/*! ./CompletedPage */ \"./src/pageClass/CompletedPage.ts\"));\nconst deviceDetection_1 = __webpack_require__(/*! ../helper/deviceDetection */ \"./src/helper/deviceDetection.ts\");\nconst continueOnMobileDialog_1 = __importDefault(__webpack_require__(/*! ../components/continueOnMobileDialog */ \"./src/components/continueOnMobileDialog.ts\"));\nclass StartPage extends MainPage_1.default {\n constructor(mainScreenId, displayMode, skipSummaryPage = false, enableImageDebug = false) {\n super(mainScreenId, displayMode, skipSummaryPage, enableImageDebug);\n this.verificationTypeMap = {\n [verification_1.VERIFICATION_TYPE.IDENTITY_DOC]: {\n title: (0, translations_1.$t)(\"national_identity_document_title\"),\n description: (0, translations_1.$t)(\"national_identity_document_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/id-card.webp */ \"./src/assets/img/firstPageVerificationIcon/id-card.webp\"),\n },\n [verification_1.VERIFICATION_TYPE.SELFIE]: {\n title: (0, translations_1.$t)(\"selfie_title\"),\n description: (0, translations_1.$t)(\"selfie_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/selfie.webp */ \"./src/assets/img/firstPageVerificationIcon/selfie.webp\"),\n },\n [verification_1.VERIFICATION_TYPE.CREDIT_CARD]: {\n title: (0, translations_1.$t)(\"cc_title\"),\n description: (0, translations_1.$t)(\"cc_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/credit-card.webp */ \"./src/assets/img/firstPageVerificationIcon/credit-card.webp\"),\n },\n [verification_1.VERIFICATION_TYPE.PROOF_OF_ADDRESS]: {\n title: (0, translations_1.$t)(\"poa_title\"),\n description: (0, translations_1.$t)(\"poa_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/poa.webp */ \"./src/assets/img/firstPageVerificationIcon/poa.webp\"),\n },\n };\n }\n render(isReset = true) {\n if (isReset)\n (0, stepper_1.resetMainStep)();\n this.renderContent(this.createPage());\n }\n createPage() {\n const verificationType = uisdk_1.pwInstance.verificationTypes[stepper_1.mainStep];\n (0, stepper_1.incrementStep)();\n const { title, description, icon: vIcon, } = this.verificationTypeMap[verificationType];\n const firstPageDiv = document.createElement(\"div\");\n firstPageDiv.classList.add(\"pw-flex\", \"pw-flex-col\", \"pw-h-full\", \"pw-overflow-y-hidden\");\n // Header navigation (fixed at top)\n const navigationDiv = document.createElement(\"div\");\n navigationDiv.classList.add(\"pw-relative\", \"pw-text-center\", \"pw-px-4\", \"pw-pt-3\", \"pw-pb-3\");\n // Merchant logo\n const merchantLogo = new merchantLogo_1.default();\n const merchantLogoElement = merchantLogo.render();\n navigationDiv.appendChild(merchantLogoElement);\n // - stepper\n const stepperNum = (0, stepper_1.getStepByType)(verificationType);\n const currentStep = (0, stepper_1.getCurrentStepNumber)(verificationType); // check here\n if (stepperNum > 1) {\n // Use getCurrentStepNumber() to get the actual UI step number - check here\n const stepper = new stepper_2.default();\n const stepperElement = stepper.render(currentStep, stepperNum);\n navigationDiv.appendChild(stepperElement);\n }\n // - close btn\n if (this.displayMode === 'in-page') {\n const closeButton = document.createElement(\"div\");\n closeButton.classList.add(\"pw-absolute\", \"pw-right-5\", \"pw-top-4\");\n const closeIcon = (0, getGoogleIcon_1.getGoogleIcon)(\"close\");\n closeButton.appendChild(closeIcon);\n closeButton.addEventListener(\"click\", () => this.openLeavePageDialog());\n navigationDiv.appendChild(closeButton);\n }\n firstPageDiv.appendChild(navigationDiv);\n // Main content wrapper - centered and growable\n const contentDiv = document.createElement(\"div\");\n contentDiv.classList.add(\"pw-flex\", \"pw-flex-col\", \"pw-items-center\", \"pw-justify-center\", \"pw-grow\", \"pw-min-h-0\", \"pw-overflow-y-auto\", \"pw-px-4\");\n firstPageDiv.appendChild(contentDiv);\n // body content\n // - image\n const iconContainerDiv = document.createElement(\"div\");\n iconContainerDiv.classList.add(\"pw-flex\", \"pw-justify-center\", \"pw-mb-4\");\n const iconDiv = document.createElement(\"div\");\n iconDiv.style.boxShadow = \"0px -10px 15px 0px #0000001A\";\n iconDiv.style.borderRadius = \"20px 20px 0px 0px\";\n iconDiv.classList.add(\"pw-text-center\", \"pw-px-6\", \"pw-pt-6\", \"pw-pb-2\");\n const icon = document.createElement(\"img\");\n icon.setAttribute(\"src\", vIcon);\n icon.setAttribute(\"alt\", \"eKYC Verification\");\n iconDiv.appendChild(icon);\n iconContainerDiv.appendChild(iconDiv);\n contentDiv.appendChild(iconContainerDiv);\n // - header description\n const wordingDiv = document.createElement(\"div\");\n wordingDiv.classList.add(\"pw-text-center\", \"pw-mb-3\");\n const titleDiv = document.createElement(\"div\");\n titleDiv.classList.add(\"pw-text-2xl\", \"pw-font-medium\", \"pw-mb-3\");\n titleDiv.innerHTML = title;\n wordingDiv.appendChild(titleDiv);\n // - description (hidden for ID and Selfie verification)\n if (verificationType !== verification_1.VERIFICATION_TYPE.IDENTITY_DOC &&\n verificationType !== verification_1.VERIFICATION_TYPE.SELFIE) {\n const descriptionDiv = document.createElement(\"div\");\n descriptionDiv.classList.add(\"pw-text-secondary\", \"pw-text-sm\");\n descriptionDiv.innerHTML = description;\n wordingDiv.appendChild(descriptionDiv);\n }\n contentDiv.appendChild(wordingDiv);\n // Tips section (only for ID, Selfie, Credit Card - not POA)\n const tipsCard = this.createTipsCard(verificationType);\n if (tipsCard) {\n tipsCard.classList.add(\"pw-w-full\", \"pw-mb-4\");\n contentDiv.appendChild(tipsCard);\n }\n // Action buttons section (separate from footer)\n const buttonsDiv = document.createElement(\"div\");\n buttonsDiv.classList.add(\"pw-flex\", \"pw-flex-col\", // Stack buttons vertically\n \"pw-items-center\", // Center buttons horizontally\n \"pw-w-full\", \"pw-mt-6\");\n // - button\n const startNowButton = (0, components_1.createPrimaryButton)((0, translations_1.$t)(\"btn_start_now\"));\n startNowButton.classList.add(\"pw-mb-3\");\n startNowButton.addEventListener(\"click\", () => this.onStartNow(verificationType));\n buttonsDiv.appendChild(startNowButton);\n // - Continue on Mobile button (only show on desktop AND only on the first page of the flow)\n // Note: mainStep is incremented at the start of createPage(), so first page has mainStep === 1\n if (!(0, deviceDetection_1.isMobileDevice)() && stepper_1.mainStep === 1) {\n const continueOnMobileButton = (0, components_1.createSecondaryButton)((0, translations_1.$t)(\"btn_continue_on_mobile\"));\n continueOnMobileButton.classList.add(\"pw-mb-3\");\n continueOnMobileButton.addEventListener(\"click\", () => this.onClickContinueOnMobile(verificationType));\n buttonsDiv.appendChild(continueOnMobileButton);\n }\n contentDiv.appendChild(buttonsDiv);\n // Footer section (sticky to bottom, separate from buttons)\n const footerDiv = document.createElement(\"div\");\n footerDiv.classList.add(\"pw-flex\", \"pw-justify-center\", \"pw-items-center\", \"pw-w-full\", \"pw-pb-4\");\n const footer = new footer_1.default().render();\n footerDiv.appendChild(footer);\n firstPageDiv.appendChild(footerDiv);\n return firstPageDiv;\n }\n /**\n * Create tips card for relevant verification types (ID, Selfie, Credit Card).\n * Uses same grey card design as continueOnMobileDialog, with default text color.\n * Returns null for POA (no camera tips).\n */\n createTipsCard(verificationType) {\n if (verificationType === verification_1.VERIFICATION_TYPE.PROOF_OF_ADDRESS) {\n return null;\n }\n const tipsCard = document.createElement(\"div\");\n tipsCard.classList.add(\"pw-box-border\", \"pw-bg-grey-2\", \"pw-p-3\", \"pw-rounded-lg\", \"pw-text-grey-10\", \"pw-text-sm\", // 14px for tips content\n \"pw-w-full\", // 100% on mobile (parent has pw-px-4 for 16px edge spacing)\n \"pw-md:pw-max-w-[480px]\", // 480px max width on desktop\n \"pw-mx-auto\");\n const tipsTitle = document.createElement(\"div\");\n tipsTitle.classList.add(\"pw-font-bold\", \"pw-mb-2\", \"pw-text-grey-10\");\n tipsTitle.textContent = (0, translations_1.$t)(\"tips\");\n // Add subtitle for credit card type\n let subtitle = null;\n if (verificationType === verification_1.VERIFICATION_TYPE.CREDIT_CARD) {\n subtitle = document.createElement(\"div\");\n subtitle.classList.add(\"pw-mb-2\", \"pw-text-secondary\");\n subtitle.textContent = (0, translations_1.$t)(\"cc_tip_title\");\n }\n const ul = document.createElement(\"ul\");\n ul.classList.add(\"pw-list-disc\", \"pw-pl-5\", \"pw-m-0\", \"pw-space-y-1\");\n let tipItems = [];\n if (verificationType === verification_1.VERIFICATION_TYPE.IDENTITY_DOC) {\n tipItems = [\n (0, translations_1.$t)(\"id_tip_1\", { cardType: (0, translations_1.$t)(\"card\").toLowerCase() }),\n (0, translations_1.$t)(\"id_tip_2\"),\n (0, translations_1.$t)(\"id_tip_3\"),\n ];\n }\n else if (verificationType === verification_1.VERIFICATION_TYPE.SELFIE) {\n tipItems = [\n (0, translations_1.$t)(\"selfie_tip_1\"),\n (0, translations_1.$t)(\"selfie_tip_2\"),\n (0, translations_1.$t)(\"selfie_tip_3\"),\n (0, translations_1.$t)(\"selfie_tip_4\"),\n ];\n }\n else if (verificationType === verification_1.VERIFICATION_TYPE.CREDIT_CARD) {\n tipItems = [(0, translations_1.$t)(\"cc_tip_1\"), (0, translations_1.$t)(\"cc_tip_2\"), (0, translations_1.$t)(\"cc_tip_3\")];\n }\n for (const text of tipItems) {\n const li = document.createElement(\"li\");\n li.classList.add(\"pw-text-secondary\");\n li.textContent = text;\n ul.appendChild(li);\n }\n tipsCard.appendChild(tipsTitle);\n if (subtitle)\n tipsCard.appendChild(subtitle);\n tipsCard.appendChild(ul);\n // Add bottom text for credit card type\n if (verificationType === verification_1.VERIFICATION_TYPE.CREDIT_CARD) {\n const bottomText1 = document.createElement(\"div\");\n bottomText1.classList.add(\"pw-mt-3\", \"pw-text-secondary\");\n bottomText1.textContent = (0, translations_1.$t)(\"cc_tip_bottom_1\");\n tipsCard.appendChild(bottomText1);\n const bottomText2 = document.createElement(\"div\");\n bottomText2.classList.add(\"pw-mt-2\", \"pw-text-info\");\n bottomText2.textContent = (0, translations_1.$t)(\"cc_tip_bottom_2\");\n tipsCard.appendChild(bottomText2);\n }\n return tipsCard;\n }\n onStartNow(verificationType) {\n switch (verificationType) {\n case verification_1.VERIFICATION_TYPE.IDENTITY_DOC: {\n this.clearScreen();\n const verifyId = new VerifyId_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage, this.enableImageDebug);\n verifyId.render();\n break;\n }\n case verification_1.VERIFICATION_TYPE.SELFIE: {\n const startSelfie = new StartSelfie_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n startSelfie.render();\n break;\n }\n case verification_1.VERIFICATION_TYPE.CREDIT_CARD: {\n const verifyCc = new VerifyCc_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage, this.enableImageDebug);\n verifyCc.render();\n break;\n }\n case verification_1.VERIFICATION_TYPE.PROOF_OF_ADDRESS: {\n this.clearScreen();\n const verifyPoa = new VerifyPoa_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n verifyPoa.render();\n }\n }\n }\n onClickContinueOnMobile(verificationType) {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n // Create continue on mobile dialog instance\n const dialog = new continueOnMobileDialog_1.default();\n // Show dialog with QR code\n yield dialog.show(this.mainScreenId, () => {\n // complete callback\n this.clearScreen();\n // Redirect to completed page\n const completedPage = new CompletedPage_1.default(this.mainScreenId, this.displayMode);\n completedPage.render();\n }, (error) => {\n // error callback\n if (error) {\n console.error('Error polling verification result', error);\n this.clearScreen();\n this.openErrorPage(error);\n }\n });\n }\n catch (error) {\n console.error('Error showing continue on mobile dialog:', error);\n // Fall back to regular flow\n this.onStartNow(verificationType);\n }\n });\n }\n}\nexports[\"default\"] = StartPage;\n\n\n//# sourceURL=webpack://PWUISDK/./src/pageClass/StartPage.ts?");
3926
+ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nconst getGoogleIcon_1 = __webpack_require__(/*! ../helper/getGoogleIcon */ \"./src/helper/getGoogleIcon.ts\");\nconst stepper_1 = __webpack_require__(/*! ../helper/stepper */ \"./src/helper/stepper.ts\");\nconst uisdk_1 = __webpack_require__(/*! ../uisdk */ \"./src/uisdk.ts\");\nconst verification_1 = __webpack_require__(/*! ../constant/verification */ \"./src/constant/verification.ts\");\nconst footer_1 = __importDefault(__webpack_require__(/*! ../components/footer */ \"./src/components/footer.ts\"));\nconst MainPage_1 = __importDefault(__webpack_require__(/*! ../classes/MainPage */ \"./src/classes/MainPage.ts\"));\nconst StartSelfie_1 = __importDefault(__webpack_require__(/*! ./StartSelfie */ \"./src/pageClass/StartSelfie.ts\"));\nconst stepper_2 = __importDefault(__webpack_require__(/*! ../components/stepper */ \"./src/components/stepper.ts\"));\nconst merchantLogo_1 = __importDefault(__webpack_require__(/*! ../components/merchantLogo */ \"./src/components/merchantLogo.ts\"));\nconst VerifyCc_1 = __importDefault(__webpack_require__(/*! ./VerifyCc */ \"./src/pageClass/VerifyCc.ts\"));\nconst VerifyId_1 = __importDefault(__webpack_require__(/*! ./VerifyId */ \"./src/pageClass/VerifyId.ts\"));\nconst VerifyPoa_1 = __importDefault(__webpack_require__(/*! ./VerifyPoa */ \"./src/pageClass/VerifyPoa.ts\"));\nconst CompletedPage_1 = __importDefault(__webpack_require__(/*! ./CompletedPage */ \"./src/pageClass/CompletedPage.ts\"));\nconst deviceDetection_1 = __webpack_require__(/*! ../helper/deviceDetection */ \"./src/helper/deviceDetection.ts\");\nconst continueOnMobileDialog_1 = __importDefault(__webpack_require__(/*! ../components/continueOnMobileDialog */ \"./src/components/continueOnMobileDialog.ts\"));\nclass StartPage extends MainPage_1.default {\n constructor(mainScreenId, displayMode, skipSummaryPage = false, enableImageDebug = false) {\n super(mainScreenId, displayMode, skipSummaryPage, enableImageDebug);\n this.verificationTypeMap = {\n [verification_1.VERIFICATION_TYPE.IDENTITY_DOC]: {\n title: (0, translations_1.$t)(\"national_identity_document_title\"),\n description: (0, translations_1.$t)(\"national_identity_document_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/id-card.webp */ \"./src/assets/img/firstPageVerificationIcon/id-card.webp\"),\n },\n [verification_1.VERIFICATION_TYPE.SELFIE]: {\n title: (0, translations_1.$t)(\"selfie_title\"),\n description: (0, translations_1.$t)(\"selfie_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/selfie.webp */ \"./src/assets/img/firstPageVerificationIcon/selfie.webp\"),\n },\n [verification_1.VERIFICATION_TYPE.CREDIT_CARD]: {\n title: (0, translations_1.$t)(\"cc_title\"),\n description: (0, translations_1.$t)(\"cc_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/credit-card.webp */ \"./src/assets/img/firstPageVerificationIcon/credit-card.webp\"),\n },\n [verification_1.VERIFICATION_TYPE.PROOF_OF_ADDRESS]: {\n title: (0, translations_1.$t)(\"poa_title\"),\n description: (0, translations_1.$t)(\"poa_desc\"),\n icon: __webpack_require__(/*! ../assets/img/firstPageVerificationIcon/poa.webp */ \"./src/assets/img/firstPageVerificationIcon/poa.webp\"),\n },\n };\n }\n render(isReset = true) {\n if (isReset)\n (0, stepper_1.resetMainStep)();\n this.renderContent(this.createPage());\n }\n createPage() {\n const verificationType = uisdk_1.pwInstance.verificationTypes[stepper_1.mainStep];\n (0, stepper_1.incrementStep)();\n const { title, description, icon: vIcon, } = this.verificationTypeMap[verificationType];\n const firstPageDiv = document.createElement(\"div\");\n firstPageDiv.classList.add(\"pw-flex\", \"pw-flex-col\", \"pw-h-full\", \"pw-overflow-y-hidden\");\n // Header navigation (fixed at top)\n const navigationDiv = document.createElement(\"div\");\n navigationDiv.classList.add(\"pw-relative\", \"pw-text-center\", \"pw-px-4\", \"pw-pt-3\", \"pw-pb-3\");\n // Merchant logo\n const merchantLogo = new merchantLogo_1.default();\n const merchantLogoElement = merchantLogo.render();\n navigationDiv.appendChild(merchantLogoElement);\n // - stepper\n const stepperNum = (0, stepper_1.getStepByType)(verificationType);\n const currentStep = (0, stepper_1.getCurrentStepNumber)(verificationType); // check here\n if (stepperNum > 1) {\n // Use getCurrentStepNumber() to get the actual UI step number - check here\n const stepper = new stepper_2.default();\n const stepperElement = stepper.render(currentStep, stepperNum);\n navigationDiv.appendChild(stepperElement);\n }\n // - close btn\n if (this.displayMode === 'in-page') {\n const closeButton = document.createElement(\"div\");\n closeButton.classList.add(\"pw-absolute\", \"pw-right-5\", \"pw-top-4\");\n const closeIcon = (0, getGoogleIcon_1.getGoogleIcon)(\"close\");\n closeButton.appendChild(closeIcon);\n closeButton.addEventListener(\"click\", () => this.openLeavePageDialog());\n navigationDiv.appendChild(closeButton);\n }\n firstPageDiv.appendChild(navigationDiv);\n // Main content wrapper - centered and growable\n const contentDiv = document.createElement(\"div\");\n contentDiv.classList.add(\"pw-flex\", \"pw-flex-col\", \"pw-items-center\", \"pw-justify-center\", \"pw-grow\", \"pw-min-h-0\", \"pw-overflow-y-auto\", \"pw-px-4\");\n firstPageDiv.appendChild(contentDiv);\n // body content\n // - image\n const iconContainerDiv = document.createElement(\"div\");\n iconContainerDiv.classList.add(\"pw-flex\", \"pw-justify-center\", \"pw-mb-4\");\n const iconDiv = document.createElement(\"div\");\n iconDiv.style.boxShadow = \"0px -10px 15px 0px #0000001A\";\n iconDiv.style.borderRadius = \"20px 20px 0px 0px\";\n iconDiv.classList.add(\"pw-text-center\", \"pw-px-6\", \"pw-pt-6\", \"pw-pb-2\");\n const icon = document.createElement(\"img\");\n icon.setAttribute(\"src\", vIcon);\n icon.setAttribute(\"alt\", \"eKYC Verification\");\n iconDiv.appendChild(icon);\n iconContainerDiv.appendChild(iconDiv);\n contentDiv.appendChild(iconContainerDiv);\n // - header description\n const wordingDiv = document.createElement(\"div\");\n wordingDiv.classList.add(\"pw-text-center\", \"pw-mb-3\");\n const titleDiv = document.createElement(\"div\");\n titleDiv.classList.add(\"pw-text-2xl\", \"pw-font-medium\", \"pw-mb-3\");\n titleDiv.innerHTML = title;\n wordingDiv.appendChild(titleDiv);\n // - description (hidden for ID and Selfie verification)\n if (verificationType !== verification_1.VERIFICATION_TYPE.IDENTITY_DOC &&\n verificationType !== verification_1.VERIFICATION_TYPE.SELFIE) {\n const descriptionDiv = document.createElement(\"div\");\n descriptionDiv.classList.add(\"pw-text-secondary\", \"pw-text-sm\");\n descriptionDiv.innerHTML = description;\n wordingDiv.appendChild(descriptionDiv);\n }\n contentDiv.appendChild(wordingDiv);\n // Tips section (only for ID, Selfie, Credit Card - not POA)\n const tipsCard = this.createTipsCard(verificationType);\n if (tipsCard) {\n tipsCard.classList.add(\"pw-w-full\", \"pw-mb-4\");\n contentDiv.appendChild(tipsCard);\n }\n // Action buttons section (separate from footer)\n const buttonsDiv = document.createElement(\"div\");\n buttonsDiv.classList.add(\"pw-flex\", \"pw-flex-col\", // Stack buttons vertically\n \"pw-items-center\", // Center buttons horizontally\n \"pw-w-full\", \"pw-mt-6\");\n // - button\n const startNowButton = (0, components_1.createPrimaryButton)((0, translations_1.$t)(\"btn_start_now\"));\n startNowButton.classList.add(\"pw-mb-3\");\n startNowButton.addEventListener(\"click\", () => this.onStartNow(verificationType));\n buttonsDiv.appendChild(startNowButton);\n // - Continue on Mobile button (only show on desktop AND only on the first page of the flow)\n // Note: mainStep is incremented at the start of createPage(), so first page has mainStep === 1\n if (!(0, deviceDetection_1.isMobileDevice)() && stepper_1.mainStep === 1) {\n const continueOnMobileButton = (0, components_1.createSecondaryButton)((0, translations_1.$t)(\"btn_continue_on_mobile\"));\n continueOnMobileButton.classList.add(\"pw-mb-3\");\n continueOnMobileButton.addEventListener(\"click\", () => this.onClickContinueOnMobile(verificationType));\n buttonsDiv.appendChild(continueOnMobileButton);\n }\n contentDiv.appendChild(buttonsDiv);\n // Footer section (sticky to bottom, separate from buttons)\n const footerDiv = document.createElement(\"div\");\n footerDiv.classList.add(\"pw-flex\", \"pw-justify-center\", \"pw-items-center\", \"pw-w-full\", \"pw-pb-4\");\n const footer = new footer_1.default().render();\n footerDiv.appendChild(footer);\n firstPageDiv.appendChild(footerDiv);\n return firstPageDiv;\n }\n /**\n * Create tips card for relevant verification types (ID, Selfie, Credit Card).\n * Uses same grey card design as continueOnMobileDialog, with default text color.\n * Returns null for POA (no camera tips).\n */\n createTipsCard(verificationType) {\n if (verificationType === verification_1.VERIFICATION_TYPE.PROOF_OF_ADDRESS) {\n return null;\n }\n const tipsCard = document.createElement(\"div\");\n tipsCard.classList.add(\"pw-box-border\", \"pw-bg-grey-2\", \"pw-p-3\", \"pw-rounded-lg\", \"pw-text-grey-10\", \"pw-text-sm\", // 14px for tips content\n \"pw-w-full\", // 100% on mobile (parent has pw-px-4 for 16px edge spacing)\n \"pw-md:pw-max-w-[480px]\", // 480px max width on desktop\n \"pw-mx-auto\");\n const tipsTitle = document.createElement(\"div\");\n tipsTitle.classList.add(\"pw-font-bold\", \"pw-mb-2\", \"pw-text-grey-10\");\n tipsTitle.textContent = (0, translations_1.$t)(\"tips\");\n // Add subtitle for credit card type\n let subtitle = null;\n if (verificationType === verification_1.VERIFICATION_TYPE.CREDIT_CARD) {\n subtitle = document.createElement(\"div\");\n subtitle.classList.add(\"pw-mb-2\", \"pw-text-secondary\");\n subtitle.textContent = (0, translations_1.$t)(\"cc_tip_title\");\n }\n const ul = document.createElement(\"ul\");\n ul.classList.add(\"pw-list-disc\", \"pw-pl-5\", \"pw-m-0\", \"pw-space-y-1\");\n let tipItems = [];\n if (verificationType === verification_1.VERIFICATION_TYPE.IDENTITY_DOC) {\n tipItems = [\n (0, translations_1.$t)(\"id_tip_1\", { cardType: (0, translations_1.$t)(\"card\").toLowerCase() }),\n (0, translations_1.$t)(\"id_tip_2\"),\n (0, translations_1.$t)(\"id_tip_3\"),\n ];\n }\n else if (verificationType === verification_1.VERIFICATION_TYPE.SELFIE) {\n tipItems = [\n (0, translations_1.$t)(\"selfie_tip_1\"),\n (0, translations_1.$t)(\"selfie_tip_2\"),\n (0, translations_1.$t)(\"selfie_tip_3\"),\n (0, translations_1.$t)(\"selfie_tip_4\"),\n ];\n }\n else if (verificationType === verification_1.VERIFICATION_TYPE.CREDIT_CARD) {\n tipItems = [(0, translations_1.$t)(\"cc_tip_1\"), (0, translations_1.$t)(\"cc_tip_2\"), (0, translations_1.$t)(\"cc_tip_3\")];\n }\n for (const text of tipItems) {\n const li = document.createElement(\"li\");\n li.classList.add(\"pw-text-secondary\");\n li.textContent = text;\n ul.appendChild(li);\n }\n tipsCard.appendChild(tipsTitle);\n if (subtitle)\n tipsCard.appendChild(subtitle);\n tipsCard.appendChild(ul);\n // Add bottom text for credit card type\n if (verificationType === verification_1.VERIFICATION_TYPE.CREDIT_CARD) {\n const bottomText1 = document.createElement(\"div\");\n bottomText1.classList.add(\"pw-mt-3\", \"pw-text-secondary\");\n bottomText1.textContent = (0, translations_1.$t)(\"cc_tip_bottom_1\");\n tipsCard.appendChild(bottomText1);\n const bottomText2 = document.createElement(\"div\");\n bottomText2.classList.add(\"pw-mt-2\", \"pw-text-info\");\n bottomText2.textContent = (0, translations_1.$t)(\"cc_tip_bottom_2\");\n tipsCard.appendChild(bottomText2);\n }\n return tipsCard;\n }\n onStartNow(verificationType) {\n switch (verificationType) {\n case verification_1.VERIFICATION_TYPE.IDENTITY_DOC: {\n this.clearScreen();\n const verifyId = new VerifyId_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage, this.enableImageDebug);\n verifyId.render();\n break;\n }\n case verification_1.VERIFICATION_TYPE.SELFIE: {\n const startSelfie = new StartSelfie_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage, this.enableImageDebug);\n startSelfie.render();\n break;\n }\n case verification_1.VERIFICATION_TYPE.CREDIT_CARD: {\n const verifyCc = new VerifyCc_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage, this.enableImageDebug);\n verifyCc.render();\n break;\n }\n case verification_1.VERIFICATION_TYPE.PROOF_OF_ADDRESS: {\n this.clearScreen();\n const verifyPoa = new VerifyPoa_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n verifyPoa.render();\n }\n }\n }\n onClickContinueOnMobile(verificationType) {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n // Create continue on mobile dialog instance\n const dialog = new continueOnMobileDialog_1.default();\n // Show dialog with QR code\n yield dialog.show(this.mainScreenId, () => {\n // complete callback\n this.clearScreen();\n // Redirect to completed page\n const completedPage = new CompletedPage_1.default(this.mainScreenId, this.displayMode);\n completedPage.render();\n }, (error) => {\n // error callback\n if (error) {\n console.error('Error polling verification result', error);\n this.clearScreen();\n this.openErrorPage(error);\n }\n });\n }\n catch (error) {\n console.error('Error showing continue on mobile dialog:', error);\n // Fall back to regular flow\n this.onStartNow(verificationType);\n }\n });\n }\n}\nexports[\"default\"] = StartPage;\n\n\n//# sourceURL=webpack://PWUISDK/./src/pageClass/StartPage.ts?");
3927
3927
 
3928
3928
  /***/ }),
3929
3929
 
@@ -3934,7 +3934,7 @@ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _argument
3934
3934
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
3935
3935
 
3936
3936
  "use strict";
3937
- eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst face_camera_1 = __importDefault(__webpack_require__(/*! ../plugins/face-camera */ \"./src/plugins/face-camera.ts\"));\nconst uisdk_1 = __webpack_require__(/*! ../uisdk */ \"./src/uisdk.ts\");\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\n// pages\nconst MainPage_1 = __importDefault(__webpack_require__(/*! ../classes/MainPage */ \"./src/classes/MainPage.ts\"));\nconst SubmissionLimit_1 = __importDefault(__webpack_require__(/*! ./SubmissionLimit */ \"./src/pageClass/SubmissionLimit.ts\"));\nconst AnalyzePage_1 = __importDefault(__webpack_require__(/*! ./AnalyzePage */ \"./src/pageClass/AnalyzePage.ts\"));\n// components\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nconst baseDialog_1 = __importDefault(__webpack_require__(/*! ../components/baseDialog */ \"./src/components/baseDialog.ts\"));\nclass StartSelfie extends MainPage_1.default {\n constructor(mainScreenId, displayMode, skipSummaryPage = false) {\n super(mainScreenId, displayMode, skipSummaryPage);\n this.cameraId = \"pw-camera-container\";\n }\n render() {\n // create div\n const screen = document.getElementById(this.mainScreenId);\n const cameraDiv = document.createElement(\"div\");\n cameraDiv.setAttribute(\"id\", this.cameraId);\n screen === null || screen === void 0 ? void 0 : screen.appendChild(cameraDiv);\n // start camera init\n const faceCamera = new face_camera_1.default(this.cameraId, this.mainScreenId);\n faceCamera.init();\n faceCamera.listenToSelfieCapture((e) => __awaiter(this, void 0, void 0, function* () {\n var _a, _b;\n try {\n faceCamera.pauseSmileFace();\n yield this.uploadSelfie(e.detail);\n faceCamera.stopVideoStream();\n // Determine next step based on verification types\n // Sequence is always ID → Selfie (if both exist)\n const verificationTypes = uisdk_1.pwInstance.verificationTypes;\n const firstVerification = verificationTypes[0];\n // Case 1: ID + Selfie combo → go to ID analyze page\n if (firstVerification === 'national_identity_document') {\n const analyzePage = new AnalyzePage_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n return analyzePage.render(\"id\");\n }\n // Case 2: Selfie only → show completion\n const analyzePage = new AnalyzePage_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n return analyzePage.render();\n }\n catch (err) {\n // 1. when exceed max attempt, redirect to submission error page\n if (err.type &&\n [\n \"openApi/max-selfie-attempt\",\n \"openApi/max-session-attempt\",\n \"openApi/limit-exceed\",\n \"openApi/session-id-expired\",\n \"attempt-exceeded\",\n \"session-id-expired\",\n ].includes(err.type)) {\n faceCamera.stopVideoStream();\n this.redirectToSubmissionLimitPage();\n return;\n }\n // 2. when selfie is exposed, redirect to selfie error page\n else if (err.type && err.type === \"openApi/img-exposed\") {\n // redirect to selfie error page\n let isRetake = false;\n const pwErrorPayload = (_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.payload;\n if (!!pwErrorPayload)\n isRetake = !!pwErrorPayload.is_retriable;\n this.openImageBlurDialog(isRetake, faceCamera);\n return;\n }\n // 3. redirect to unexpected error page\n else {\n faceCamera.stopVideoStream();\n this.clearScreen();\n this.openErrorPage(err);\n }\n }\n }));\n }\n openImageBlurDialog(isRetake, faceCamera) {\n const errorDialog = new baseDialog_1.default();\n errorDialog.render(this.mainScreenId, (0, translations_1.$t)(\"error_selfie\"), isRetake ? (0, translations_1.$t)(\"btn_retake\") : (0, translations_1.$t)(\"btn_proceed\"), () => {\n if (isRetake)\n faceCamera.resumeSmileFace();\n else\n this.redirectToSubmissionLimitPage();\n });\n }\n redirectToSubmissionLimitPage() {\n this.clearScreen();\n // redirect to submission error page\n const submissionLimit = new SubmissionLimit_1.default(this.mainScreenId, this.displayMode);\n return submissionLimit.render();\n }\n uploadSelfie(detail) {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n // show loading spinner in full pg\n (0, components_1.createFullLoading)(this.cameraId);\n const { image, livenessScore } = detail;\n yield uisdk_1.pwInstance.uploadSelfie({\n selfie_base64: image.croppedImage,\n selfie_base64_full: image.fullImage,\n liveness_score: livenessScore,\n });\n }\n finally {\n // hide loading spinner in full pg\n (0, components_1.hideFullLoading)(this.cameraId);\n }\n });\n }\n}\nexports[\"default\"] = StartSelfie;\n\n\n//# sourceURL=webpack://PWUISDK/./src/pageClass/StartSelfie.ts?");
3937
+ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst face_camera_1 = __importDefault(__webpack_require__(/*! ../plugins/face-camera */ \"./src/plugins/face-camera.ts\"));\nconst uisdk_1 = __webpack_require__(/*! ../uisdk */ \"./src/uisdk.ts\");\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\n// pages\nconst MainPage_1 = __importDefault(__webpack_require__(/*! ../classes/MainPage */ \"./src/classes/MainPage.ts\"));\nconst SubmissionLimit_1 = __importDefault(__webpack_require__(/*! ./SubmissionLimit */ \"./src/pageClass/SubmissionLimit.ts\"));\nconst AnalyzePage_1 = __importDefault(__webpack_require__(/*! ./AnalyzePage */ \"./src/pageClass/AnalyzePage.ts\"));\n// components\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nconst baseDialog_1 = __importDefault(__webpack_require__(/*! ../components/baseDialog */ \"./src/components/baseDialog.ts\"));\nclass StartSelfie extends MainPage_1.default {\n constructor(mainScreenId, displayMode, skipSummaryPage = false, enableImageDebug = false) {\n super(mainScreenId, displayMode, skipSummaryPage, enableImageDebug);\n this.cameraId = \"pw-camera-container\";\n }\n render() {\n // create div\n const screen = document.getElementById(this.mainScreenId);\n const cameraDiv = document.createElement(\"div\");\n cameraDiv.setAttribute(\"id\", this.cameraId);\n screen === null || screen === void 0 ? void 0 : screen.appendChild(cameraDiv);\n // start camera init\n const faceCamera = new face_camera_1.default(this.cameraId, this.mainScreenId);\n faceCamera.init();\n faceCamera.listenToSelfieCapture((e) => __awaiter(this, void 0, void 0, function* () {\n var _a, _b;\n try {\n faceCamera.pauseSmileFace();\n yield this.uploadSelfie(e.detail);\n faceCamera.stopVideoStream();\n // Determine next step based on verification types\n // Sequence is always ID → Selfie (if both exist)\n const verificationTypes = uisdk_1.pwInstance.verificationTypes;\n const firstVerification = verificationTypes[0];\n // Case 1: ID + Selfie combo → go to ID analyze page\n if (firstVerification === 'national_identity_document') {\n const analyzePage = new AnalyzePage_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n return analyzePage.render(\"id\");\n }\n // Case 2: Selfie only → show completion\n const analyzePage = new AnalyzePage_1.default(this.mainScreenId, this.displayMode, this.skipSummaryPage);\n return analyzePage.render();\n }\n catch (err) {\n // 1. when exceed max attempt, redirect to submission error page\n if (err.type &&\n [\n \"openApi/max-selfie-attempt\",\n \"openApi/max-session-attempt\",\n \"openApi/limit-exceed\",\n \"openApi/session-id-expired\",\n \"attempt-exceeded\",\n \"session-id-expired\",\n ].includes(err.type)) {\n faceCamera.stopVideoStream();\n this.redirectToSubmissionLimitPage();\n return;\n }\n // 2. when selfie is exposed, redirect to selfie error page\n else if (err.type && err.type === \"openApi/img-exposed\") {\n // redirect to selfie error page\n let isRetake = false;\n const pwErrorPayload = (_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.payload;\n if (!!pwErrorPayload)\n isRetake = !!pwErrorPayload.is_retriable;\n this.openImageBlurDialog(isRetake, faceCamera);\n return;\n }\n // 3. redirect to unexpected error page\n else {\n faceCamera.stopVideoStream();\n this.clearScreen();\n this.openErrorPage(err);\n }\n }\n }));\n }\n openImageBlurDialog(isRetake, faceCamera) {\n const errorDialog = new baseDialog_1.default();\n errorDialog.render(this.mainScreenId, (0, translations_1.$t)(\"error_selfie\"), isRetake ? (0, translations_1.$t)(\"btn_retake\") : (0, translations_1.$t)(\"btn_proceed\"), () => {\n if (isRetake)\n faceCamera.resumeSmileFace();\n else\n this.redirectToSubmissionLimitPage();\n });\n }\n redirectToSubmissionLimitPage() {\n this.clearScreen();\n // redirect to submission error page\n const submissionLimit = new SubmissionLimit_1.default(this.mainScreenId, this.displayMode);\n return submissionLimit.render();\n }\n uploadSelfie(detail) {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n // show loading spinner in full pg\n (0, components_1.createFullLoading)(this.cameraId);\n const { image, livenessScore } = detail;\n yield uisdk_1.pwInstance.uploadSelfie({\n selfie_base64: image.croppedImage,\n selfie_base64_full: image.fullImage,\n liveness_score: livenessScore,\n });\n }\n finally {\n // hide loading spinner in full pg\n (0, components_1.hideFullLoading)(this.cameraId);\n }\n });\n }\n}\nexports[\"default\"] = StartSelfie;\n\n\n//# sourceURL=webpack://PWUISDK/./src/pageClass/StartSelfie.ts?");
3938
3938
 
3939
3939
  /***/ }),
3940
3940
 
@@ -4033,7 +4033,7 @@ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _argument
4033
4033
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
4034
4034
 
4035
4035
  "use strict";
4036
- eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst face_detection_1 = __importDefault(__webpack_require__(/*! ./face-detection */ \"./src/plugins/face-detection.ts\"));\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\nconst deviceDetection_1 = __webpack_require__(/*! ../helper/deviceDetection */ \"./src/helper/deviceDetection.ts\");\nconst camera_1 = __webpack_require__(/*! ../models/camera */ \"./src/models/camera.ts\");\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nconst baseDialog_1 = __importDefault(__webpack_require__(/*! ../components/baseDialog */ \"./src/components/baseDialog.ts\"));\nconst navigationBar_1 = __importDefault(__webpack_require__(/*! ../components/navigationBar */ \"./src/components/navigationBar.ts\"));\nconst footer_1 = __importDefault(__webpack_require__(/*! ../components/footer */ \"./src/components/footer.ts\"));\nconst imagesHelper_1 = __webpack_require__(/*! ../helper/imagesHelper */ \"./src/helper/imagesHelper.ts\");\nclass FaceCamera {\n constructor(cameraId, mainScreenId = \"\") {\n this.cameraTimeLimit = 90000;\n this.videoElement = null;\n this.canvasElement = null;\n this.overlayElement = null;\n this.titleElement = null;\n this.cameraId = cameraId;\n this.mainScreenId = mainScreenId;\n }\n isMobile() {\n // Use extracted helper function\n return (0, deviceDetection_1.isMobileDevice)();\n }\n captureImage() {\n var _a, _b, _c, _d, _e, _f;\n return __awaiter(this, void 0, void 0, function* () {\n const bitmap = this.videoElement;\n // 1. full image\n let canvas = document.createElement(\"canvas\");\n let context = canvas.getContext(\"2d\");\n canvas.width = bitmap.videoWidth;\n canvas.height = bitmap.videoHeight;\n context.drawImage(bitmap, 0, 0, bitmap.videoWidth, bitmap.videoHeight);\n // 2. cropped image — region corresponds exactly to what the overlay shows\n let cropCanvas = document.createElement(\"canvas\");\n let cropContext = cropCanvas.getContext(\"2d\");\n cropCanvas.width = bitmap.videoWidth;\n cropCanvas.height = bitmap.videoHeight;\n cropContext.drawImage(bitmap, 0, 0, bitmap.videoWidth, bitmap.videoHeight);\n // Scale factor: stream pixels per display pixel\n const scaleX = bitmap.videoWidth / ((_b = (_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : bitmap.videoWidth);\n const scaleY = bitmap.videoHeight / ((_d = (_c = this.videoElement) === null || _c === void 0 ? void 0 : _c.clientHeight) !== null && _d !== void 0 ? _d : bitmap.videoHeight);\n // Use overlay's actual on-screen position as the crop region\n const overlayRect = (_e = this.overlayElement) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();\n const videoRect = (_f = this.videoElement) === null || _f === void 0 ? void 0 : _f.getBoundingClientRect();\n let cropX, cropY, cropW, cropH;\n if (overlayRect && videoRect) {\n cropX = Math.round((overlayRect.left - videoRect.left) * scaleX);\n cropY = Math.round((overlayRect.top - videoRect.top) * scaleY);\n cropW = Math.round(overlayRect.width * scaleX);\n cropH = Math.round(overlayRect.height * scaleY);\n }\n else {\n // Fallback: derive from calculateHeightNWidth\n const { width, height } = this.faceDetectionSdk.calculateHeightNWidth(bitmap.videoWidth, bitmap.videoHeight);\n cropW = width;\n cropH = height;\n cropX = Math.round((bitmap.videoWidth - cropW) / 2);\n cropY = Math.round((bitmap.videoHeight - cropH) / 2);\n }\n // Clamp to stream bounds\n cropX = Math.max(0, cropX);\n cropY = Math.max(0, cropY);\n cropW = Math.min(cropW, bitmap.videoWidth - cropX);\n cropH = Math.min(cropH, bitmap.videoHeight - cropY);\n const imgData = cropContext.getImageData(cropX, cropY, cropW, cropH);\n cropCanvas.width = cropW;\n cropCanvas.height = cropH;\n cropContext.putImageData(imgData, 0, 0);\n // 3. resize the canvas\n try {\n canvas = (0, imagesHelper_1.resizeCanvas)(canvas, imagesHelper_1.maxFullImage.width, imagesHelper_1.maxFullImage.height);\n cropCanvas = (0, imagesHelper_1.resizeCanvas)(cropCanvas, imagesHelper_1.maxCroppedImage.width, imagesHelper_1.maxCroppedImage.height);\n }\n catch (err) {\n console.error(\"face resize image error\", err);\n }\n // 4. construct payload - convert to desired file format\n const payload = {\n fullImage: canvas.toDataURL(\"image/jpeg\"),\n croppedImage: cropCanvas.toDataURL(\"image/jpeg\"),\n };\n return payload;\n });\n }\n init() {\n try {\n // show loading spinner in full pg\n (0, components_1.createFullLoading)(this.cameraId, \"Initializing Camera...\");\n // 1. Draw the camera display\n this.drawCameraDisplay();\n // 2. Setup related SDK\n const { videoElement, canvasElement, overlayElement, titleElement } = this;\n this.faceDetectionSdk = new face_detection_1.default({\n cameraId: this.cameraId,\n videoElement,\n canvasElement,\n overlayElement,\n titleElement,\n });\n // 3. Get the camera permission and trigger the selfie detection\n this.cameraInit();\n // 4. Trigger event after 3 seconds of face detection\n this.faceDetectionSdk.setCaptureImage((livenessScore) => __awaiter(this, void 0, void 0, function* () {\n var _a;\n const image = yield this.captureImage();\n const event = new CustomEvent(\"selfieCapture\", {\n detail: { image, livenessScore },\n });\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);\n }));\n // 5. Face camera custom events listeners\n const description = document.getElementById(\"pw-camera-description\");\n this.faceDetectionSdk.listenToUserNoSmile(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_smile_at_camera\");\n }\n });\n this.faceDetectionSdk.listenToUserSmiled(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_smile_seconds\");\n }\n });\n this.faceDetectionSdk.listenToUserSmiledButNotLiveness(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_neutral_expression\");\n }\n });\n this.faceDetectionSdk.listenToLookStraight(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_looks_straight\");\n }\n });\n this.faceDetectionSdk.listenToPlaceFace(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_within_frame\");\n }\n });\n // 6. Start timer to close camera\n this.timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {\n this.stopVideoStream();\n // open idle dialog\n const idleDialog = new baseDialog_1.default();\n idleDialog.render(this.mainScreenId, (0, translations_1.$t)(\"idle_message\"), (0, translations_1.$t)(\"btn_okay\"));\n }), this.cameraTimeLimit);\n }\n finally {\n if (!this.faceDetectionSdk ||\n this.faceDetectionSdk.getLoadedModelState() !== \"LOADING\")\n (0, components_1.hideFullLoading)(this.cameraId);\n }\n }\n drawCameraDisplay() {\n const mainBody = document.getElementById(this.cameraId);\n if (!mainBody)\n return;\n // 1. header section\n const header = document.createElement(\"div\");\n header.id = camera_1.ELEMENT_IDS.HEADER;\n // header.classList.add(\"camera-header-area\");\n header.classList.add(\"pw-absolute\", \"pw-z-[2]\", \"pw-w-full\", \"pw-text-white\");\n const navigationDiv = new navigationBar_1.default().render(() => {\n this.stopVideoStream();\n });\n header.appendChild(navigationDiv);\n const titleDiv = document.createElement(\"div\");\n titleDiv.id = \"pw-camera-title\";\n titleDiv.classList.add(\"pw-text-2xl\", \"pw-text-center\", \"pw-mb-4\", \"pw-px-5\");\n const body = document.createElement(\"div\");\n body.id = camera_1.ELEMENT_IDS.BODY;\n body.classList.add(\"camera-body-area\");\n const videoContainer = document.createElement(\"div\");\n videoContainer.id = camera_1.ELEMENT_IDS.VIDEO_CONTAINER;\n videoContainer.classList.add(\"video-container\");\n const overlayContainer = document.createElement(\"div\");\n overlayContainer.id = camera_1.ELEMENT_IDS.OVERLAY_CONTAINER;\n overlayContainer.classList.add(\"overlay-container\");\n const overlayElement = document.createElement(\"div\");\n overlayElement.id = camera_1.ELEMENT_IDS.OVERLAY;\n overlayElement.classList.add(\"overlay-element\");\n overlayElement.classList.add(\"pw-hidden\");\n overlayElement.classList.add(\"pw-relative\");\n // Set Description — full viewport width so text is not constrained by oval\n const descriptionDiv = document.createElement(\"div\");\n descriptionDiv.classList.add(\"pw-text-center\", \"pw-px-5\", \"pw-text-xl\", \"pw-mb-4\", \"pw-absolute\", \"pw-text-white\");\n descriptionDiv.style.zIndex = \"1\";\n descriptionDiv.style.left = \"50%\";\n descriptionDiv.style.marginLeft = \"-50vw\";\n descriptionDiv.style.bottom = \"100%\";\n descriptionDiv.style.transform = \"translateY(-20px)\";\n descriptionDiv.style.width = \"100vw\";\n descriptionDiv.style.boxSizing = \"border-box\";\n descriptionDiv.id = \"pw-camera-description\";\n descriptionDiv.innerHTML = (0, translations_1.$t)(\"face_within_frame\");\n this.descriptionElement = descriptionDiv;\n overlayElement.appendChild(descriptionDiv);\n const canvasElement = document.createElement(\"canvas\");\n canvasElement.id = camera_1.ELEMENT_IDS.CANVAS;\n canvasElement.classList.add(\"video-element\");\n canvasElement.classList.add(\"canvas-element\");\n canvasElement.style.transform = \"scaleX(-1)\";\n const videoElement = document.createElement(\"video\");\n videoElement.id = camera_1.ELEMENT_IDS.VIDEO;\n videoElement.autoplay = true;\n videoElement.playsInline = true;\n videoElement.preload = \"auto\";\n videoElement.loop = true;\n videoElement.classList.add(\"video-element\");\n videoElement.style.transform = \"scaleX(-1)\";\n // green tick icon - inside overlayElement so it aligns with overlay (same fix as card-camera)\n const iconElement = document.createElement(\"span\");\n iconElement.id = \"pw-camera-check-icon\";\n iconElement.classList.add(\"pw-hidden\", \"pw-absolute\", \"pw-inset-0\", \"pw-flex\", \"pw-items-center\", \"pw-justify-center\");\n const checkIcon = document.createElement(\"span\");\n checkIcon.classList.add(\"material-icons\", \"pw-text-green-500\", \"pw-text-4xl\", \"pw-rounded-full\");\n checkIcon.style.fontSize = \"48px\";\n checkIcon.innerHTML = \"check_circle\";\n iconElement.appendChild(checkIcon);\n // 2.1\n this.videoElement = videoElement;\n this.overlayElement = overlayElement;\n this.canvasElement = canvasElement;\n overlayElement.appendChild(iconElement);\n overlayContainer.appendChild(overlayElement);\n videoContainer.appendChild(overlayContainer);\n videoContainer.appendChild(canvasElement);\n videoContainer.appendChild(videoElement);\n body.appendChild(videoContainer);\n // 3. Footer - Powered by pipwave\n const footerWrapper = document.createElement(\"div\");\n footerWrapper.classList.add(\"pw-absolute\", \"pw-bottom-0\", \"pw-left-0\", \"pw-right-0\", \"pw-pb-4\", \"pw-z-[2]\", \"pw-flex\", \"pw-justify-center\", \"pw-items-center\", \"pw-text-white\");\n const footer = new footer_1.default().render(true);\n footerWrapper.appendChild(footer);\n mainBody.appendChild(footerWrapper);\n // 4. append child\n mainBody.classList.add(\"camera-bg\");\n mainBody.appendChild(header);\n mainBody.appendChild(body);\n }\n loadVideoStream(videoElement) {\n const initialConstraints = {\n facingMode: \"user\",\n width: {\n ideal: 1280, // 1280, 1024, 640\n },\n height: {\n ideal: 960, // 960, 768, 480\n },\n video: true,\n };\n // Load the video stream\n const nav = window.navigator.mediaDevices\n ? window.navigator.mediaDevices\n : window.navigator;\n if (!nav)\n return;\n nav\n .getUserMedia({ video: initialConstraints })\n .then((stream) => {\n videoElement.srcObject = stream;\n })\n .catch((err) => {\n console.error(\"Error accessing the camera:\", err);\n });\n }\n cameraInit() {\n var _a;\n if (!this.videoElement)\n return;\n this.loadVideoStream(this.videoElement);\n // video event listeners\n this.videoElement.addEventListener(\"loadedmetadata\", () => __awaiter(this, void 0, void 0, function* () {\n var _b;\n this.faceDetectionSdk.init();\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.classList.remove(\"pw-hidden\");\n // Set initial video dimensions based on orientation\n this.resizeElement();\n }));\n this.videoElement.addEventListener(\"resize\", () => {\n this.resizeElement();\n });\n window.addEventListener(\"resize\", () => {\n this.resizeElement();\n });\n (_a = screen.orientation) === null || _a === void 0 ? void 0 : _a.addEventListener(\"change\", () => {\n const orientationType = screen.orientation.type;\n if (!orientationType || !this.isMobile)\n return;\n if ([\"landscape-primary\", \"landscape-secondary\"].includes(orientationType)) {\n // TO ADD DIALOG ASK USER TO USE POTRAIT VIEW\n }\n else if ([\"portrait-secondary\", \"portrait-primary\"].includes(orientationType)) {\n // TO BE CONFIRM IF NEED CLOSE DIALOG\n }\n });\n }\n stopVideoStream() {\n if (this.videoElement && this.videoElement.srcObject) {\n const stream = this.videoElement.srcObject;\n const tracks = stream.getTracks();\n tracks.forEach(function (track) {\n track.stop();\n });\n this.videoElement.srcObject = null;\n }\n if (this.timer)\n clearTimeout(this.timer);\n const cameraDiv = document.getElementById(this.cameraId);\n cameraDiv === null || cameraDiv === void 0 ? void 0 : cameraDiv.remove();\n (0, components_1.hideFullLoading)(this.cameraId);\n }\n resizeElement() {\n const videoContainer = document.getElementById(camera_1.ELEMENT_IDS.VIDEO_CONTAINER);\n const videoElement = this.videoElement;\n if (videoElement && videoElement.videoWidth && videoElement.videoHeight) {\n const vpW = window.innerWidth;\n const vpH = window.innerHeight;\n const videoAspect = videoElement.videoWidth / videoElement.videoHeight;\n // Fit the container to the camera's native aspect ratio within the viewport\n let containerW;\n let containerH;\n if (vpW / vpH > videoAspect) {\n // Viewport is wider than video — constrain by height\n containerH = vpH;\n containerW = vpH * videoAspect;\n }\n else {\n // Viewport is taller than video — constrain by width\n containerW = vpW;\n containerH = vpW / videoAspect;\n }\n if (videoContainer) {\n videoContainer.style.width = `${containerW}px`;\n videoContainer.style.height = `${containerH}px`;\n }\n videoElement.style.width = \"100%\";\n videoElement.style.height = \"100%\";\n videoElement.style.minWidth = \"\";\n videoElement.style.minHeight = \"\";\n }\n this.faceDetectionSdk.resizeElement();\n }\n listenToSelfieCapture(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"selfieCapture\", (e) => {\n cb(e);\n });\n }\n pauseSmileFace() {\n var _a, _b;\n return __awaiter(this, void 0, void 0, function* () {\n // stop the video\n (_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.pause();\n yield ((_b = this.faceDetectionSdk) === null || _b === void 0 ? void 0 : _b.disableDetection());\n // stop idle timeout\n if (this.timer) {\n clearTimeout(this.timer);\n }\n // clear description\n const description = document.getElementById(\"pw-camera-description\");\n if (description)\n description.innerHTML = \"\";\n // show green tick icon\n const checkIcon = document.getElementById(\"pw-camera-check-icon\");\n checkIcon === null || checkIcon === void 0 ? void 0 : checkIcon.classList.remove(\"pw-hidden\");\n });\n }\n resumeSmileFace() {\n var _a, _b;\n return __awaiter(this, void 0, void 0, function* () {\n // resume the video\n (_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.play();\n yield ((_b = this.faceDetectionSdk) === null || _b === void 0 ? void 0 : _b.startDetection());\n // start idle timeout\n this.timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {\n this.stopVideoStream();\n // open idle dialog\n const idleDialog = new baseDialog_1.default();\n idleDialog.render(this.mainScreenId, (0, translations_1.$t)(\"idle_message\"), (0, translations_1.$t)(\"btn_okay\"));\n }), this.cameraTimeLimit);\n // hide green tick icon\n const checkIcon = document.getElementById(\"pw-camera-check-icon\");\n checkIcon === null || checkIcon === void 0 ? void 0 : checkIcon.classList.add(\"pw-hidden\");\n // remove green circle\n const overlayElement = document.getElementById(\"overlayElement\");\n if (overlayElement)\n overlayElement.classList.remove(\"overlay-element--active\");\n // close all the background loading\n (0, components_1.hideFullLoading)(this.cameraId);\n });\n }\n}\nexports[\"default\"] = FaceCamera;\n\n\n//# sourceURL=webpack://PWUISDK/./src/plugins/face-camera.ts?");
4036
+ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst face_detection_1 = __importDefault(__webpack_require__(/*! ./face-detection */ \"./src/plugins/face-detection.ts\"));\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\nconst deviceDetection_1 = __webpack_require__(/*! ../helper/deviceDetection */ \"./src/helper/deviceDetection.ts\");\nconst MainPage_1 = __webpack_require__(/*! ../classes/MainPage */ \"./src/classes/MainPage.ts\");\nconst camera_1 = __webpack_require__(/*! ../models/camera */ \"./src/models/camera.ts\");\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nconst baseDialog_1 = __importDefault(__webpack_require__(/*! ../components/baseDialog */ \"./src/components/baseDialog.ts\"));\nconst navigationBar_1 = __importDefault(__webpack_require__(/*! ../components/navigationBar */ \"./src/components/navigationBar.ts\"));\nconst footer_1 = __importDefault(__webpack_require__(/*! ../components/footer */ \"./src/components/footer.ts\"));\nconst imagesHelper_1 = __webpack_require__(/*! ../helper/imagesHelper */ \"./src/helper/imagesHelper.ts\");\nclass FaceCamera {\n constructor(cameraId, mainScreenId = \"\") {\n this.cameraTimeLimit = 90000;\n this.videoElement = null;\n this.canvasElement = null;\n this.overlayElement = null;\n this.titleElement = null;\n this.cameraId = cameraId;\n this.mainScreenId = mainScreenId;\n }\n isMobile() {\n // Use extracted helper function\n return (0, deviceDetection_1.isMobileDevice)();\n }\n captureImage() {\n var _a, _b, _c, _d, _e, _f;\n return __awaiter(this, void 0, void 0, function* () {\n const bitmap = this.videoElement;\n // 1. full image\n let canvas = document.createElement(\"canvas\");\n let context = canvas.getContext(\"2d\");\n canvas.width = bitmap.videoWidth;\n canvas.height = bitmap.videoHeight;\n context.drawImage(bitmap, 0, 0, bitmap.videoWidth, bitmap.videoHeight);\n // 2. cropped image — region corresponds exactly to what the overlay shows\n let cropCanvas = document.createElement(\"canvas\");\n let cropContext = cropCanvas.getContext(\"2d\");\n cropCanvas.width = bitmap.videoWidth;\n cropCanvas.height = bitmap.videoHeight;\n cropContext.drawImage(bitmap, 0, 0, bitmap.videoWidth, bitmap.videoHeight);\n // Scale factor: stream pixels per display pixel\n const scaleX = bitmap.videoWidth / ((_b = (_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : bitmap.videoWidth);\n const scaleY = bitmap.videoHeight / ((_d = (_c = this.videoElement) === null || _c === void 0 ? void 0 : _c.clientHeight) !== null && _d !== void 0 ? _d : bitmap.videoHeight);\n // Use overlay's actual on-screen position as the crop region\n const overlayRect = (_e = this.overlayElement) === null || _e === void 0 ? void 0 : _e.getBoundingClientRect();\n const videoRect = (_f = this.videoElement) === null || _f === void 0 ? void 0 : _f.getBoundingClientRect();\n let cropX, cropY, cropW, cropH;\n if (overlayRect && videoRect) {\n cropX = Math.round((overlayRect.left - videoRect.left) * scaleX);\n cropY = Math.round((overlayRect.top - videoRect.top) * scaleY);\n cropW = Math.round(overlayRect.width * scaleX);\n cropH = Math.round(overlayRect.height * scaleY);\n }\n else {\n // Fallback: derive from calculateHeightNWidth\n const { width, height } = this.faceDetectionSdk.calculateHeightNWidth(bitmap.videoWidth, bitmap.videoHeight);\n cropW = width;\n cropH = height;\n cropX = Math.round((bitmap.videoWidth - cropW) / 2);\n cropY = Math.round((bitmap.videoHeight - cropH) / 2);\n }\n // Clamp to stream bounds\n cropX = Math.max(0, cropX);\n cropY = Math.max(0, cropY);\n cropW = Math.min(cropW, bitmap.videoWidth - cropX);\n cropH = Math.min(cropH, bitmap.videoHeight - cropY);\n const imgData = cropContext.getImageData(cropX, cropY, cropW, cropH);\n cropCanvas.width = cropW;\n cropCanvas.height = cropH;\n cropContext.putImageData(imgData, 0, 0);\n // 3. resize the canvas\n try {\n canvas = (0, imagesHelper_1.resizeCanvas)(canvas, imagesHelper_1.maxFullImage.width, imagesHelper_1.maxFullImage.height);\n cropCanvas = (0, imagesHelper_1.resizeCanvas)(cropCanvas, imagesHelper_1.maxCroppedImage.width, imagesHelper_1.maxCroppedImage.height);\n }\n catch (err) {\n console.error(\"face resize image error\", err);\n }\n // 4. construct payload - convert to desired file format\n const payload = {\n fullImage: canvas.toDataURL(\"image/jpeg\"),\n croppedImage: cropCanvas.toDataURL(\"image/jpeg\"),\n };\n if (MainPage_1.enableImageDebug) {\n if (payload.fullImage)\n this.downloadImage(payload.fullImage, `selfie-full-${canvas.width}x${canvas.height}.jpg`);\n if (payload.croppedImage)\n this.downloadImage(payload.croppedImage, `selfie-cropped-${cropCanvas.width}x${cropCanvas.height}.jpg`);\n }\n return payload;\n });\n }\n init() {\n try {\n // show loading spinner in full pg\n (0, components_1.createFullLoading)(this.cameraId, \"Initializing Camera...\");\n // 1. Draw the camera display\n this.drawCameraDisplay();\n // 2. Setup related SDK\n const { videoElement, canvasElement, overlayElement, titleElement } = this;\n this.faceDetectionSdk = new face_detection_1.default({\n cameraId: this.cameraId,\n videoElement,\n canvasElement,\n overlayElement,\n titleElement,\n });\n // 3. Get the camera permission and trigger the selfie detection\n this.cameraInit();\n // 4. Trigger event after 3 seconds of face detection\n this.faceDetectionSdk.setCaptureImage((livenessScore) => __awaiter(this, void 0, void 0, function* () {\n var _a;\n const image = yield this.captureImage();\n const event = new CustomEvent(\"selfieCapture\", {\n detail: { image, livenessScore },\n });\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);\n }));\n // 5. Face camera custom events listeners\n const description = document.getElementById(\"pw-camera-description\");\n this.faceDetectionSdk.listenToUserNoSmile(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_smile_at_camera\");\n }\n });\n this.faceDetectionSdk.listenToUserSmiled(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_smile_seconds\");\n }\n });\n this.faceDetectionSdk.listenToUserSmiledButNotLiveness(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_neutral_expression\");\n }\n });\n this.faceDetectionSdk.listenToLookStraight(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_looks_straight\");\n }\n });\n this.faceDetectionSdk.listenToPlaceFace(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_within_frame\");\n }\n });\n this.faceDetectionSdk.listenToFaceTooFar(() => {\n if (description) {\n description.innerHTML = (0, translations_1.$t)(\"face_too_far\");\n }\n });\n // 6. Start timer to close camera\n this.timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {\n this.stopVideoStream();\n // open idle dialog\n const idleDialog = new baseDialog_1.default();\n idleDialog.render(this.mainScreenId, (0, translations_1.$t)(\"idle_message\"), (0, translations_1.$t)(\"btn_okay\"));\n }), this.cameraTimeLimit);\n }\n finally {\n if (!this.faceDetectionSdk ||\n this.faceDetectionSdk.getLoadedModelState() !== \"LOADING\")\n (0, components_1.hideFullLoading)(this.cameraId);\n }\n }\n drawCameraDisplay() {\n const mainBody = document.getElementById(this.cameraId);\n if (!mainBody)\n return;\n // 1. header section\n const header = document.createElement(\"div\");\n header.id = camera_1.ELEMENT_IDS.HEADER;\n // header.classList.add(\"camera-header-area\");\n header.classList.add(\"pw-absolute\", \"pw-z-[2]\", \"pw-w-full\", \"pw-text-white\");\n const navigationDiv = new navigationBar_1.default().render(() => {\n this.stopVideoStream();\n });\n header.appendChild(navigationDiv);\n const titleDiv = document.createElement(\"div\");\n titleDiv.id = \"pw-camera-title\";\n titleDiv.classList.add(\"pw-text-2xl\", \"pw-text-center\", \"pw-mb-4\", \"pw-px-5\");\n const body = document.createElement(\"div\");\n body.id = camera_1.ELEMENT_IDS.BODY;\n body.classList.add(\"camera-body-area\");\n const videoContainer = document.createElement(\"div\");\n videoContainer.id = camera_1.ELEMENT_IDS.VIDEO_CONTAINER;\n videoContainer.classList.add(\"video-container\");\n const overlayContainer = document.createElement(\"div\");\n overlayContainer.id = camera_1.ELEMENT_IDS.OVERLAY_CONTAINER;\n overlayContainer.classList.add(\"overlay-container\");\n const overlayElement = document.createElement(\"div\");\n overlayElement.id = camera_1.ELEMENT_IDS.OVERLAY;\n overlayElement.classList.add(\"overlay-element\");\n overlayElement.classList.add(\"pw-hidden\");\n overlayElement.classList.add(\"pw-relative\");\n // Set Description — full viewport width so text is not constrained by oval\n const descriptionDiv = document.createElement(\"div\");\n descriptionDiv.classList.add(\"pw-text-center\", \"pw-px-5\", \"pw-text-xl\", \"pw-mb-4\", \"pw-absolute\", \"pw-text-white\");\n descriptionDiv.style.zIndex = \"1\";\n descriptionDiv.style.left = \"50%\";\n descriptionDiv.style.marginLeft = \"-50vw\";\n descriptionDiv.style.bottom = \"100%\";\n descriptionDiv.style.transform = \"translateY(-20px)\";\n descriptionDiv.style.width = \"100vw\";\n descriptionDiv.style.boxSizing = \"border-box\";\n descriptionDiv.id = \"pw-camera-description\";\n descriptionDiv.innerHTML = (0, translations_1.$t)(\"face_within_frame\");\n this.descriptionElement = descriptionDiv;\n overlayElement.appendChild(descriptionDiv);\n const canvasElement = document.createElement(\"canvas\");\n canvasElement.id = camera_1.ELEMENT_IDS.CANVAS;\n canvasElement.classList.add(\"video-element\");\n canvasElement.classList.add(\"canvas-element\");\n canvasElement.style.transform = \"scaleX(-1)\";\n const videoElement = document.createElement(\"video\");\n videoElement.id = camera_1.ELEMENT_IDS.VIDEO;\n videoElement.autoplay = true;\n videoElement.playsInline = true;\n videoElement.preload = \"auto\";\n videoElement.loop = true;\n videoElement.classList.add(\"video-element\");\n videoElement.style.transform = \"scaleX(-1)\";\n // green tick icon - inside overlayElement so it aligns with overlay (same fix as card-camera)\n const iconElement = document.createElement(\"span\");\n iconElement.id = \"pw-camera-check-icon\";\n iconElement.classList.add(\"pw-hidden\", \"pw-absolute\", \"pw-inset-0\", \"pw-flex\", \"pw-items-center\", \"pw-justify-center\");\n const checkIcon = document.createElement(\"span\");\n checkIcon.classList.add(\"material-icons\", \"pw-text-green-500\", \"pw-text-4xl\", \"pw-rounded-full\");\n checkIcon.style.fontSize = \"48px\";\n checkIcon.innerHTML = \"check_circle\";\n iconElement.appendChild(checkIcon);\n // 2.1\n this.videoElement = videoElement;\n this.overlayElement = overlayElement;\n this.canvasElement = canvasElement;\n overlayElement.appendChild(iconElement);\n overlayContainer.appendChild(overlayElement);\n videoContainer.appendChild(overlayContainer);\n videoContainer.appendChild(canvasElement);\n videoContainer.appendChild(videoElement);\n body.appendChild(videoContainer);\n // 3. Footer - Powered by pipwave\n const footerWrapper = document.createElement(\"div\");\n footerWrapper.classList.add(\"pw-absolute\", \"pw-bottom-0\", \"pw-left-0\", \"pw-right-0\", \"pw-pb-4\", \"pw-z-[2]\", \"pw-flex\", \"pw-justify-center\", \"pw-items-center\", \"pw-text-white\");\n const footer = new footer_1.default().render(true);\n footerWrapper.appendChild(footer);\n mainBody.appendChild(footerWrapper);\n // 4. append child\n mainBody.classList.add(\"camera-bg\");\n mainBody.appendChild(header);\n mainBody.appendChild(body);\n }\n loadVideoStream(videoElement) {\n const initialConstraints = {\n facingMode: \"user\",\n width: {\n ideal: 1280, // 1280, 1024, 640\n },\n height: {\n ideal: 960, // 960, 768, 480\n },\n video: true,\n };\n // Load the video stream\n const nav = window.navigator.mediaDevices\n ? window.navigator.mediaDevices\n : window.navigator;\n if (!nav)\n return;\n nav\n .getUserMedia({ video: initialConstraints })\n .then((stream) => {\n videoElement.srcObject = stream;\n })\n .catch((err) => {\n console.error(\"Error accessing the camera:\", err);\n });\n }\n cameraInit() {\n var _a;\n if (!this.videoElement)\n return;\n this.loadVideoStream(this.videoElement);\n // video event listeners\n this.videoElement.addEventListener(\"loadedmetadata\", () => __awaiter(this, void 0, void 0, function* () {\n var _b;\n this.faceDetectionSdk.init();\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.classList.remove(\"pw-hidden\");\n // Set initial video dimensions based on orientation\n this.resizeElement();\n }));\n this.videoElement.addEventListener(\"resize\", () => {\n this.resizeElement();\n });\n window.addEventListener(\"resize\", () => {\n this.resizeElement();\n });\n (_a = screen.orientation) === null || _a === void 0 ? void 0 : _a.addEventListener(\"change\", () => {\n const orientationType = screen.orientation.type;\n if (!orientationType || !this.isMobile)\n return;\n if ([\"landscape-primary\", \"landscape-secondary\"].includes(orientationType)) {\n // TO ADD DIALOG ASK USER TO USE POTRAIT VIEW\n }\n else if ([\"portrait-secondary\", \"portrait-primary\"].includes(orientationType)) {\n // TO BE CONFIRM IF NEED CLOSE DIALOG\n }\n });\n }\n stopVideoStream() {\n if (this.videoElement && this.videoElement.srcObject) {\n const stream = this.videoElement.srcObject;\n const tracks = stream.getTracks();\n tracks.forEach(function (track) {\n track.stop();\n });\n this.videoElement.srcObject = null;\n }\n if (this.timer)\n clearTimeout(this.timer);\n const cameraDiv = document.getElementById(this.cameraId);\n cameraDiv === null || cameraDiv === void 0 ? void 0 : cameraDiv.remove();\n (0, components_1.hideFullLoading)(this.cameraId);\n }\n resizeElement() {\n const videoContainer = document.getElementById(camera_1.ELEMENT_IDS.VIDEO_CONTAINER);\n const videoElement = this.videoElement;\n if (videoElement && videoElement.videoWidth && videoElement.videoHeight) {\n const vpW = window.innerWidth;\n const vpH = window.innerHeight;\n const videoAspect = videoElement.videoWidth / videoElement.videoHeight;\n // Fit the container to the camera's native aspect ratio within the viewport\n let containerW;\n let containerH;\n if (vpW / vpH > videoAspect) {\n // Viewport is wider than video — constrain by height\n containerH = vpH;\n containerW = vpH * videoAspect;\n }\n else {\n // Viewport is taller than video — constrain by width\n containerW = vpW;\n containerH = vpW / videoAspect;\n }\n if (videoContainer) {\n videoContainer.style.width = `${containerW}px`;\n videoContainer.style.height = `${containerH}px`;\n }\n videoElement.style.width = \"100%\";\n videoElement.style.height = \"100%\";\n videoElement.style.minWidth = \"\";\n videoElement.style.minHeight = \"\";\n }\n this.faceDetectionSdk.resizeElement();\n }\n listenToSelfieCapture(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"selfieCapture\", (e) => {\n cb(e);\n });\n }\n pauseSmileFace() {\n var _a, _b;\n return __awaiter(this, void 0, void 0, function* () {\n // stop the video\n (_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.pause();\n yield ((_b = this.faceDetectionSdk) === null || _b === void 0 ? void 0 : _b.disableDetection());\n // stop idle timeout\n if (this.timer) {\n clearTimeout(this.timer);\n }\n // clear description\n const description = document.getElementById(\"pw-camera-description\");\n if (description)\n description.innerHTML = \"\";\n // show green tick icon\n const checkIcon = document.getElementById(\"pw-camera-check-icon\");\n checkIcon === null || checkIcon === void 0 ? void 0 : checkIcon.classList.remove(\"pw-hidden\");\n });\n }\n resumeSmileFace() {\n var _a, _b;\n return __awaiter(this, void 0, void 0, function* () {\n // resume the video\n (_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.play();\n yield ((_b = this.faceDetectionSdk) === null || _b === void 0 ? void 0 : _b.startDetection());\n // start idle timeout\n this.timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {\n this.stopVideoStream();\n // open idle dialog\n const idleDialog = new baseDialog_1.default();\n idleDialog.render(this.mainScreenId, (0, translations_1.$t)(\"idle_message\"), (0, translations_1.$t)(\"btn_okay\"));\n }), this.cameraTimeLimit);\n // hide green tick icon\n const checkIcon = document.getElementById(\"pw-camera-check-icon\");\n checkIcon === null || checkIcon === void 0 ? void 0 : checkIcon.classList.add(\"pw-hidden\");\n // remove green circle\n const overlayElement = document.getElementById(\"overlayElement\");\n if (overlayElement)\n overlayElement.classList.remove(\"overlay-element--active\");\n // close all the background loading\n (0, components_1.hideFullLoading)(this.cameraId);\n });\n }\n downloadImage(dataUrl, filename) {\n const link = document.createElement(\"a\");\n link.href = dataUrl;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n }\n}\nexports[\"default\"] = FaceCamera;\n\n\n//# sourceURL=webpack://PWUISDK/./src/plugins/face-camera.ts?");
4037
4037
 
4038
4038
  /***/ }),
4039
4039
 
@@ -4044,7 +4044,7 @@ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _argument
4044
4044
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
4045
4045
 
4046
4046
  "use strict";
4047
- eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nlet loadedModelState = \"NOT_LOADED\";\nlet faceApiInstance;\n// direct use faceapi if it is already import in client's project (especially angular)\nfaceApiInstance =\n typeof faceapi !== \"undefined\" ? faceapi : __webpack_require__(/*! face-api.js */ \"./node_modules/face-api.js/build/es6/index.js\");\nclass FACEDETECTIONSDK {\n constructor(val) {\n this.cameraId = \"\";\n this.isDone = false; // use to check if the face detection is done\n this.prevEmotionalState = \"\";\n this.currenEmotionaltState = \"\";\n this.isLiveness = false;\n // constant variable\n this.face_api_detection_options = new faceApiInstance.TinyFaceDetectorOptions({\n inputSize: 224,\n });\n this.faceTrack_settings = {\n contrast: 3,\n brightness: 0.5,\n threshold: 100,\n minCorrelation: 0.17,\n minScore: 0.6,\n };\n // html element\n this.videoElement = null;\n this.canvasElement = null;\n this.overlayElement = null;\n this.titleElement = null;\n this.instructionElement = null;\n Object.assign(this, val);\n }\n getLoadedModelState() {\n return loadedModelState;\n }\n setCaptureImage(captureImage) {\n this.captureImage = captureImage;\n }\n // get the face position\n getFaceXY(pos) {\n const posF = {\n top: Math.min.apply(Math, pos.map(function (o) {\n return o.y;\n })),\n bottom: Math.max.apply(Math, pos.map(function (o) {\n return o.y;\n })),\n left: Math.min.apply(Math, pos.map(function (o) {\n return o.x;\n })),\n right: Math.max.apply(Math, pos.map(function (o) {\n return o.x;\n })),\n };\n return {\n x: posF[\"left\"],\n y: posF[\"top\"],\n w: posF[\"right\"] - posF[\"left\"],\n h: posF[\"bottom\"] - posF[\"top\"],\n };\n }\n // get the circle area position\n getCircleXY() {\n if (!this.canvasElement || !this.overlayElement)\n return { x: 0, y: 0, w: 0, h: 0 };\n // canvas rectangle position\n const posR = this.canvasElement.getBoundingClientRect();\n // circle position\n const posC = this.overlayElement.getBoundingClientRect();\n return {\n // get the coord x and y of the circle inside the canvas rectangle\n x: posC.x - posR.x,\n y: posC.y - posR.y,\n w: posC.width,\n h: posC.height,\n };\n }\n // to detect if your face is looking straight at the camera\n isAngleDetected(pos) {\n const angleOne = (Math.atan2(Math.abs(pos[7][\"y\"] - pos[33][\"y\"]), Math.abs(pos[7][\"x\"] - pos[33][\"x\"])) *\n 180) /\n Math.PI;\n const angleTwo = (Math.atan2(Math.abs(pos[60][\"y\"] - pos[33][\"y\"]), Math.abs(pos[60][\"x\"] - pos[33][\"x\"])) *\n 180) /\n Math.PI;\n const distance1 = Math.abs(pos[0][\"x\"] - pos[33][\"x\"]);\n const distance2 = Math.abs(pos[14][\"x\"] - pos[33][\"x\"]);\n const isAngle = !((angleOne > 40 && angleOne < 93) ||\n (angleTwo > 40 && angleTwo < 93));\n const isDistance = Math.abs(distance1 - distance2) / distance1 > 0.5;\n return isAngle || isDistance;\n }\n // check if the face is inside the circle area\n isFaceDetected(pos) {\n const posCircle = this.getCircleXY();\n const posFace = this.getFaceXY(pos);\n // face-api landmarks stop at the eyebrows — the forehead above is not covered.\n // Add ~60% of landmark height as top padding to account for the unseen forehead,\n // so the oval check requires the full face (including forehead) to be inside.\n const foreheadPadding = posFace.h * 0.6;\n if (posFace.x + posFace.w < posCircle.x + posCircle.w &&\n posFace.x > posCircle.x &&\n posFace.y - foreheadPadding > posCircle.y &&\n posFace.y + posFace.h < posCircle.y + posCircle.h)\n return true;\n return false;\n }\n // check if the face emotional is changing\n detectLiveness(current) {\n this.prevEmotionalState = this.currenEmotionaltState;\n this.currenEmotionaltState = current;\n return (this.prevEmotionalState &&\n this.currenEmotionaltState &&\n this.prevEmotionalState != this.currenEmotionaltState);\n }\n // check if the face in the video is similar to the previous face\n detectSimilarFace(current) {\n this.prevFaceDescriptor = this.currentFaceDescriptor;\n this.currentFaceDescriptor = current;\n if (!this.prevFaceDescriptor || !this.currentFaceDescriptor)\n return 1;\n // the smaller the distance, the more similar the faces are\n return faceApiInstance.euclideanDistance(this.prevFaceDescriptor, this.currentFaceDescriptor);\n }\n // reset instruction html text and all those checking\n resetInstructions() {\n this.isLiveness = false;\n this.currenEmotionaltState = \"\";\n this.prevEmotionalState = \"\";\n this.prevFaceDescriptor = undefined;\n this.currentFaceDescriptor = undefined;\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.remove(\"overlay-element--active\");\n }\n checkFace(livenessScore, pos, currentExpression, currentFaceDescriptor) {\n var _a, _b, _c, _d, _e;\n const isFace = this.isFaceDetected(pos);\n // 1. check if the face is inside the circle area\n if (!isFace) {\n this.resetInstructions();\n const event = new CustomEvent(\"placeFace\");\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);\n return;\n }\n // 2. check if the face is looking straight at the camera\n else if (this.isAngleDetected(pos)) {\n this.resetInstructions();\n const event = new CustomEvent(\"lookStraight\");\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.dispatchEvent(event);\n if (this.instructionElement)\n this.instructionElement.innerHTML = (0, translations_1.$t)(\"face_looks_straight\");\n return;\n }\n // 3. check the liveness of the face\n if (this.detectLiveness(currentExpression))\n this.isLiveness = true;\n // 4. check the similarity of the face\n const isSimilarFace = this.detectSimilarFace(currentFaceDescriptor) < 0.6;\n if (this.isLiveness && !isSimilarFace) {\n this.resetInstructions();\n return;\n }\n if (currentExpression !== \"happy\") {\n const event = new CustomEvent(\"userNoSmile\");\n (_c = this.overlayElement) === null || _c === void 0 ? void 0 : _c.dispatchEvent(event);\n // this.overlayElement?.classList.add(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.remove(\"overlay-element--active\");\n }\n else if (this.isLiveness) {\n // emit event here STAY 3 seconds\n const event = new CustomEvent(\"userSmiled\");\n (_d = this.overlayElement) === null || _d === void 0 ? void 0 : _d.dispatchEvent(event);\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.add(\"overlay-element--active\");\n if (isSimilarFace &&\n this.isLiveness &&\n this.currenEmotionaltState === \"happy\" &&\n this.captureImage) {\n this.captureImage(livenessScore);\n }\n }\n else if (!this.isDone) {\n const event = new CustomEvent(\"userSmiledButNotLiveness\");\n (_e = this.overlayElement) === null || _e === void 0 ? void 0 : _e.dispatchEvent(event);\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.add(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.remove(\"overlay-element--active\");\n }\n }\n detectFace() {\n var _a, _b;\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.videoElement || !this.canvasElement || !this.overlayElement)\n return;\n const displaySize = {\n width: this.canvasElement.width,\n height: this.canvasElement.height,\n };\n const detections = yield faceApiInstance\n .detectSingleFace(this.videoElement, this.face_api_detection_options)\n .withFaceLandmarks()\n .withFaceExpressions()\n .withFaceDescriptor();\n const event = new CustomEvent(\"placeFace\");\n if (typeof detections !== \"undefined\") {\n const expressions = detections.expressions;\n const currentExpression = Object.keys(expressions).reduce((a, b) => {\n return expressions[a] >\n expressions[b]\n ? a\n : b;\n });\n const resizedDetections = faceApiInstance.resizeResults(detections, displaySize);\n const pos = resizedDetections.landmarks.positions;\n const score = detections.detection.score;\n if (score > this.faceTrack_settings.minScore && pos) {\n this.checkFace(score, pos, currentExpression, detections.descriptor);\n }\n else {\n this.resetInstructions();\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);\n }\n // draw canvas points for developer view only\n // if (typeof resizedDetections !== \"undefined\" && this.canvasElement) {\n // this.canvasElement\n // .getContext(\"2d\")\n // ?.clearRect(\n // 0,\n // 0,\n // this.canvasElement.width,\n // this.canvasElement.height\n // );\n // if (resizedDetections) {\n // faceApiInstance.draw.drawDetections(this.canvasElement, resizedDetections);\n // faceApiInstance.draw.drawFaceLandmarks(this.canvasElement, resizedDetections);\n // faceApiInstance.draw.drawFaceExpressions(\n // this.canvasElement,\n // resizedDetections\n // );\n // }\n // }\n }\n else {\n this.resetInstructions();\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.dispatchEvent(event);\n }\n if (!this.isDone)\n this.iFrameRef = requestAnimationFrame(() => this.detectFace());\n });\n }\n disableDetection() {\n return __awaiter(this, void 0, void 0, function* () {\n this.isDone = true;\n // stop face detection\n if (this.iFrameRef)\n cancelAnimationFrame(this.iFrameRef);\n this.iFrameRef = undefined;\n // reset all the instructions text\n this.resetInstructions();\n });\n }\n startDetection() {\n return __awaiter(this, void 0, void 0, function* () {\n this.isDone = false;\n // start face detection\n (0, components_1.createCountdown)(this.cameraId, 5, () => __awaiter(this, void 0, void 0, function* () {\n yield this.detectFace();\n }));\n });\n }\n // use to calculate the cropped image size / ratio\n // from ui or exact image src\n calculateHeightNWidth(width, height) {\n var _a, _b;\n const videoWidth = ((_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0;\n const videoHeight = ((_b = this.videoElement) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;\n // calculate the circle size for the image\n // based on which has the largest size: height or width\n // then the circle will be 5/6 from that smaller size\n const circleSize = videoHeight > videoWidth ? width - width / 6 : height - height / 6;\n const newWidth = (circleSize / 5) * 4.5;\n const newHeight = circleSize;\n return { width: newWidth, height: newHeight };\n }\n resizeElement() {\n var _a, _b, _c, _d;\n if (!this.videoElement || !this.canvasElement)\n return;\n const videoW = this.videoElement.clientWidth;\n const videoH = this.videoElement.clientHeight;\n // 1. resize canvas to match video size\n this.canvasElement.width = videoW;\n this.canvasElement.height = videoH;\n // 2. desired oval size (9:10 width/height)\n const OVERLAY_ASPECT_RATIO = 9 / 10; // width / height\n const OVERLAY_MAX_HEIGHT = 500;\n const MOBILE_PADDING_VW = 0.08;\n let width;\n let height;\n if (window.screen.width >= 475) {\n height = OVERLAY_MAX_HEIGHT;\n width = Math.round(height * OVERLAY_ASPECT_RATIO);\n }\n else {\n const paddingPx = window.innerWidth * MOBILE_PADDING_VW;\n width = Math.round(window.innerWidth - 2 * paddingPx);\n height = Math.round(width / OVERLAY_ASPECT_RATIO);\n }\n // 3. clamp oval to video bounds (oval must not exceed video width or height)\n if (videoW > 0 && videoH > 0) {\n const maxWidthByHeight = videoH * OVERLAY_ASPECT_RATIO;\n width = Math.min(width, videoW, maxWidthByHeight);\n height = Math.round(width / OVERLAY_ASPECT_RATIO);\n if (height > videoH) {\n height = videoH;\n width = Math.round(height * OVERLAY_ASPECT_RATIO);\n }\n }\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.style.setProperty(\"border-radius\", \"50%\");\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.style.setProperty(\"border\", \"solid white 3px\");\n (_c = this.overlayElement) === null || _c === void 0 ? void 0 : _c.style.setProperty(\"width\", `${width}px`);\n (_d = this.overlayElement) === null || _d === void 0 ? void 0 : _d.style.setProperty(\"height\", `${height}px`);\n }\n // train face-api models\n loadFaceModel() {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n if (loadedModelState !== \"NOT_LOADED\")\n return;\n const url = \"https://assets.pipwave.com/ekyc/sdk/face-models\" || 0;\n loadedModelState = \"LOADING\";\n yield Promise.all([\n faceApiInstance.loadTinyFaceDetectorModel(url),\n faceApiInstance.loadFaceLandmarkModel(url),\n faceApiInstance.loadFaceRecognitionModel(url),\n faceApiInstance.loadFaceExpressionModel(url),\n ]);\n loadedModelState = \"LOADED\";\n }\n catch (err) {\n loadedModelState = \"NOT_LOADED\";\n return Promise.reject(err);\n }\n });\n }\n init() {\n return __awaiter(this, void 0, void 0, function* () {\n // show loading spinner in full pg\n (0, components_1.createFullLoading)(this.cameraId, \"Initializing Camera...\");\n this.isDone = false;\n this.resizeElement();\n if (loadedModelState === \"NOT_LOADED\")\n yield this.loadFaceModel();\n // Wait until loadFaceModel is LOADED\n while (loadedModelState === \"LOADING\") {\n yield new Promise((resolve) => setTimeout(resolve, 500));\n }\n if (!this.iFrameRef) {\n (0, components_1.hideFullLoading)(this.cameraId);\n yield this.startDetection();\n }\n });\n }\n listenToUserNoSmile(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"userNoSmile\", () => {\n cb();\n });\n }\n listenToUserSmiled(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"userSmiled\", () => {\n cb();\n });\n }\n listenToUserSmiledButNotLiveness(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"userSmiledButNotLiveness\", () => {\n cb();\n });\n }\n listenToLookStraight(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"lookStraight\", () => {\n cb();\n });\n }\n listenToPlaceFace(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"placeFace\", () => {\n cb();\n });\n }\n}\nexports[\"default\"] = FACEDETECTIONSDK;\n\n\n//# sourceURL=webpack://PWUISDK/./src/plugins/face-detection.ts?");
4047
+ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst translations_1 = __webpack_require__(/*! ../translations */ \"./src/translations/index.ts\");\nconst components_1 = __webpack_require__(/*! ../components/components */ \"./src/components/components.ts\");\nlet loadedModelState = \"NOT_LOADED\";\nlet faceApiInstance;\n// direct use faceapi if it is already import in client's project (especially angular)\nfaceApiInstance =\n typeof faceapi !== \"undefined\" ? faceapi : __webpack_require__(/*! face-api.js */ \"./node_modules/face-api.js/build/es6/index.js\");\nclass FACEDETECTIONSDK {\n constructor(val) {\n this.cameraId = \"\";\n this.isDone = false; // use to check if the face detection is done\n this.prevEmotionalState = \"\";\n this.currenEmotionaltState = \"\";\n this.isLiveness = false;\n // set to true to enforce face-fill-ratio check (user must be close enough to camera)\n this.enforceFaceFillRatio = true;\n // set to true to enforce straight-look check during smile capture\n this.enforceLookStraight = true;\n // constant variable\n this.face_api_detection_options = new faceApiInstance.TinyFaceDetectorOptions({\n inputSize: 224,\n });\n this.faceTrack_settings = {\n contrast: 3,\n brightness: 0.5,\n threshold: 100,\n minCorrelation: 0.17,\n minScore: 0.6,\n };\n // html element\n this.videoElement = null;\n this.canvasElement = null;\n this.overlayElement = null;\n this.titleElement = null;\n this.instructionElement = null;\n Object.assign(this, val);\n }\n getLoadedModelState() {\n return loadedModelState;\n }\n setCaptureImage(captureImage) {\n this.captureImage = captureImage;\n }\n // get the face position\n getFaceXY(pos) {\n const posF = {\n top: Math.min.apply(Math, pos.map(function (o) {\n return o.y;\n })),\n bottom: Math.max.apply(Math, pos.map(function (o) {\n return o.y;\n })),\n left: Math.min.apply(Math, pos.map(function (o) {\n return o.x;\n })),\n right: Math.max.apply(Math, pos.map(function (o) {\n return o.x;\n })),\n };\n return {\n x: posF[\"left\"],\n y: posF[\"top\"],\n w: posF[\"right\"] - posF[\"left\"],\n h: posF[\"bottom\"] - posF[\"top\"],\n };\n }\n // get the circle area position\n getCircleXY() {\n if (!this.canvasElement || !this.overlayElement)\n return { x: 0, y: 0, w: 0, h: 0 };\n // canvas rectangle position\n const posR = this.canvasElement.getBoundingClientRect();\n // circle position\n const posC = this.overlayElement.getBoundingClientRect();\n return {\n // get the coord x and y of the circle inside the canvas rectangle\n x: posC.x - posR.x,\n y: posC.y - posR.y,\n w: posC.width,\n h: posC.height,\n };\n }\n // to detect if your face is looking straight at the camera\n isAngleDetected(pos) {\n const angleOne = (Math.atan2(Math.abs(pos[7][\"y\"] - pos[33][\"y\"]), Math.abs(pos[7][\"x\"] - pos[33][\"x\"])) *\n 180) /\n Math.PI;\n const angleTwo = (Math.atan2(Math.abs(pos[60][\"y\"] - pos[33][\"y\"]), Math.abs(pos[60][\"x\"] - pos[33][\"x\"])) *\n 180) /\n Math.PI;\n const distance1 = Math.abs(pos[0][\"x\"] - pos[33][\"x\"]);\n const distance2 = Math.abs(pos[14][\"x\"] - pos[33][\"x\"]);\n const isAngle = !((angleOne > 40 && angleOne < 93) ||\n (angleTwo > 40 && angleTwo < 93));\n const isDistance = Math.abs(distance1 - distance2) / distance1 > 0.5;\n return isAngle || isDistance;\n }\n // check if the face is inside the circle area\n isFaceDetected(pos) {\n const posCircle = this.getCircleXY();\n const posFace = this.getFaceXY(pos);\n // face-api landmarks stop at the eyebrows — the forehead above is not covered.\n // Add ~60% of landmark height as top padding to account for the unseen forehead,\n // so the oval check requires the full face (including forehead) to be inside.\n const foreheadPadding = posFace.h * 0.6;\n return (posFace.x + posFace.w < posCircle.x + posCircle.w &&\n posFace.x > posCircle.x &&\n posFace.y - foreheadPadding > posCircle.y &&\n posFace.y + posFace.h < posCircle.y + posCircle.h);\n }\n // check if the face fills enough of the oval (user is close enough to camera).\n // Face width and estimated full-face height (landmarks + forehead) must each\n // cover at least MIN_FACE_FILL_RATIO of the oval's dimensions.\n isFaceLargeEnough(pos) {\n const MIN_FACE_FILL_RATIO = 0.60;\n const posCircle = this.getCircleXY();\n const posFace = this.getFaceXY(pos);\n const estimatedFaceHeight = posFace.h * 1.6; // landmarks height + 60% forehead\n return (posFace.w / posCircle.w >= MIN_FACE_FILL_RATIO &&\n estimatedFaceHeight / posCircle.h >= MIN_FACE_FILL_RATIO);\n }\n // check if the face emotional is changing\n detectLiveness(current) {\n this.prevEmotionalState = this.currenEmotionaltState;\n this.currenEmotionaltState = current;\n return (this.prevEmotionalState &&\n this.currenEmotionaltState &&\n this.prevEmotionalState != this.currenEmotionaltState);\n }\n // check if the face in the video is similar to the previous face\n detectSimilarFace(current) {\n this.prevFaceDescriptor = this.currentFaceDescriptor;\n this.currentFaceDescriptor = current;\n if (!this.prevFaceDescriptor || !this.currentFaceDescriptor)\n return 1;\n // the smaller the distance, the more similar the faces are\n return faceApiInstance.euclideanDistance(this.prevFaceDescriptor, this.currentFaceDescriptor);\n }\n // reset instruction html text and all those checking\n resetInstructions() {\n this.isLiveness = false;\n this.currenEmotionaltState = \"\";\n this.prevEmotionalState = \"\";\n this.prevFaceDescriptor = undefined;\n this.currentFaceDescriptor = undefined;\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.remove(\"overlay-element--active\");\n }\n checkFace(livenessScore, pos, currentExpression, currentFaceDescriptor) {\n var _a, _b, _c, _d, _e, _f;\n const isFace = this.isFaceDetected(pos);\n // 1. check if the face is inside the circle area\n if (!isFace) {\n this.resetInstructions();\n const event = new CustomEvent(\"placeFace\");\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);\n return;\n }\n // 1b. check if the face is large enough (user not too far from camera)\n if (this.enforceFaceFillRatio && !this.isFaceLargeEnough(pos)) {\n this.resetInstructions();\n const event = new CustomEvent(\"faceTooFar\");\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.dispatchEvent(event);\n return;\n }\n // 2. check if the face is looking straight at the camera\n const isLookingStraight = !this.isAngleDetected(pos);\n if (this.enforceLookStraight && !isLookingStraight) {\n this.resetInstructions();\n const event = new CustomEvent(\"lookStraight\");\n (_c = this.overlayElement) === null || _c === void 0 ? void 0 : _c.dispatchEvent(event);\n if (this.instructionElement)\n this.instructionElement.innerHTML = (0, translations_1.$t)(\"face_looks_straight\");\n return;\n }\n // 3. check the liveness of the face\n if (this.detectLiveness(currentExpression))\n this.isLiveness = true;\n // 4. check the similarity of the face\n const isSimilarFace = this.detectSimilarFace(currentFaceDescriptor) < 0.6;\n if (this.isLiveness && !isSimilarFace) {\n this.resetInstructions();\n return;\n }\n if (currentExpression !== \"happy\") {\n const event = new CustomEvent(\"userNoSmile\");\n (_d = this.overlayElement) === null || _d === void 0 ? void 0 : _d.dispatchEvent(event);\n // this.overlayElement?.classList.add(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.remove(\"overlay-element--active\");\n }\n else if (this.isLiveness) {\n // emit event here STAY 3 seconds\n const event = new CustomEvent(\"userSmiled\");\n (_e = this.overlayElement) === null || _e === void 0 ? void 0 : _e.dispatchEvent(event);\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.add(\"overlay-element--active\");\n if (isSimilarFace &&\n this.isLiveness &&\n this.currenEmotionaltState === \"happy\" &&\n (!this.enforceLookStraight || isLookingStraight) &&\n this.captureImage) {\n this.captureImage(livenessScore);\n }\n }\n else if (!this.isDone) {\n const event = new CustomEvent(\"userSmiledButNotLiveness\");\n (_f = this.overlayElement) === null || _f === void 0 ? void 0 : _f.dispatchEvent(event);\n // this.overlayElement?.classList.remove(\"overlay-element--selfie-smile\");\n // this.overlayElement?.classList.add(\"overlay-element--selfie-neutral\");\n // this.overlayElement?.classList.remove(\"overlay-element--active\");\n }\n }\n detectFace() {\n var _a, _b;\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.videoElement || !this.canvasElement || !this.overlayElement)\n return;\n const displaySize = {\n width: this.canvasElement.width,\n height: this.canvasElement.height,\n };\n const detections = yield faceApiInstance\n .detectSingleFace(this.videoElement, this.face_api_detection_options)\n .withFaceLandmarks()\n .withFaceExpressions()\n .withFaceDescriptor();\n const event = new CustomEvent(\"placeFace\");\n if (typeof detections !== \"undefined\") {\n const expressions = detections.expressions;\n const currentExpression = Object.keys(expressions).reduce((a, b) => {\n return expressions[a] >\n expressions[b]\n ? a\n : b;\n });\n const resizedDetections = faceApiInstance.resizeResults(detections, displaySize);\n const pos = resizedDetections.landmarks.positions;\n const score = detections.detection.score;\n if (score > this.faceTrack_settings.minScore && pos) {\n this.checkFace(score, pos, currentExpression, detections.descriptor);\n }\n else {\n this.resetInstructions();\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);\n }\n // draw canvas points for developer view only\n // if (typeof resizedDetections !== \"undefined\" && this.canvasElement) {\n // this.canvasElement\n // .getContext(\"2d\")\n // ?.clearRect(\n // 0,\n // 0,\n // this.canvasElement.width,\n // this.canvasElement.height\n // );\n // if (resizedDetections) {\n // faceApiInstance.draw.drawDetections(this.canvasElement, resizedDetections);\n // faceApiInstance.draw.drawFaceLandmarks(this.canvasElement, resizedDetections);\n // faceApiInstance.draw.drawFaceExpressions(\n // this.canvasElement,\n // resizedDetections\n // );\n // }\n // }\n }\n else {\n this.resetInstructions();\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.dispatchEvent(event);\n }\n if (!this.isDone)\n this.iFrameRef = requestAnimationFrame(() => this.detectFace());\n });\n }\n disableDetection() {\n return __awaiter(this, void 0, void 0, function* () {\n this.isDone = true;\n // stop face detection\n if (this.iFrameRef)\n cancelAnimationFrame(this.iFrameRef);\n this.iFrameRef = undefined;\n // reset all the instructions text\n this.resetInstructions();\n });\n }\n startDetection() {\n return __awaiter(this, void 0, void 0, function* () {\n this.isDone = false;\n // start face detection\n (0, components_1.createCountdown)(this.cameraId, 5, () => __awaiter(this, void 0, void 0, function* () {\n yield this.detectFace();\n }));\n });\n }\n // use to calculate the cropped image size / ratio\n // from ui or exact image src\n calculateHeightNWidth(width, height) {\n var _a, _b;\n const videoWidth = ((_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0;\n const videoHeight = ((_b = this.videoElement) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;\n // calculate the circle size for the image\n // based on which has the largest size: height or width\n // then the circle will be 5/6 from that smaller size\n const circleSize = videoHeight > videoWidth ? width - width / 6 : height - height / 6;\n const newWidth = (circleSize / 5) * 4.5;\n const newHeight = circleSize;\n return { width: newWidth, height: newHeight };\n }\n resizeElement() {\n var _a, _b, _c, _d;\n if (!this.videoElement || !this.canvasElement)\n return;\n const videoW = this.videoElement.clientWidth;\n const videoH = this.videoElement.clientHeight;\n // 1. resize canvas to match video size\n this.canvasElement.width = videoW;\n this.canvasElement.height = videoH;\n // 2. desired oval size (9:10 width/height)\n const OVERLAY_ASPECT_RATIO = 9 / 10; // width / height\n const OVERLAY_MAX_HEIGHT = 500;\n const MOBILE_PADDING_VW = 0.08;\n let width;\n let height;\n if (window.screen.width >= 475) {\n height = OVERLAY_MAX_HEIGHT;\n width = Math.round(height * OVERLAY_ASPECT_RATIO);\n }\n else {\n const paddingPx = window.innerWidth * MOBILE_PADDING_VW;\n width = Math.round(window.innerWidth - 2 * paddingPx);\n height = Math.round(width / OVERLAY_ASPECT_RATIO);\n }\n // 3. clamp oval to video bounds (oval must not exceed video width or height)\n if (videoW > 0 && videoH > 0) {\n const maxWidthByHeight = videoH * OVERLAY_ASPECT_RATIO;\n width = Math.min(width, videoW, maxWidthByHeight);\n height = Math.round(width / OVERLAY_ASPECT_RATIO);\n if (height > videoH) {\n height = videoH;\n width = Math.round(height * OVERLAY_ASPECT_RATIO);\n }\n }\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.style.setProperty(\"border-radius\", \"50%\");\n (_b = this.overlayElement) === null || _b === void 0 ? void 0 : _b.style.setProperty(\"border\", \"solid white 3px\");\n (_c = this.overlayElement) === null || _c === void 0 ? void 0 : _c.style.setProperty(\"width\", `${width}px`);\n (_d = this.overlayElement) === null || _d === void 0 ? void 0 : _d.style.setProperty(\"height\", `${height}px`);\n }\n // train face-api models\n loadFaceModel() {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n if (loadedModelState !== \"NOT_LOADED\")\n return;\n const url = \"https://assets.pipwave.com/ekyc/sdk/face-models\" || 0;\n loadedModelState = \"LOADING\";\n yield Promise.all([\n faceApiInstance.loadTinyFaceDetectorModel(url),\n faceApiInstance.loadFaceLandmarkModel(url),\n faceApiInstance.loadFaceRecognitionModel(url),\n faceApiInstance.loadFaceExpressionModel(url),\n ]);\n loadedModelState = \"LOADED\";\n }\n catch (err) {\n loadedModelState = \"NOT_LOADED\";\n return Promise.reject(err);\n }\n });\n }\n init() {\n return __awaiter(this, void 0, void 0, function* () {\n // show loading spinner in full pg\n (0, components_1.createFullLoading)(this.cameraId, \"Initializing Camera...\");\n this.isDone = false;\n this.resizeElement();\n if (loadedModelState === \"NOT_LOADED\")\n yield this.loadFaceModel();\n // Wait until loadFaceModel is LOADED\n while (loadedModelState === \"LOADING\") {\n yield new Promise((resolve) => setTimeout(resolve, 500));\n }\n if (!this.iFrameRef) {\n (0, components_1.hideFullLoading)(this.cameraId);\n yield this.startDetection();\n }\n });\n }\n listenToUserNoSmile(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"userNoSmile\", () => {\n cb();\n });\n }\n listenToUserSmiled(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"userSmiled\", () => {\n cb();\n });\n }\n listenToUserSmiledButNotLiveness(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"userSmiledButNotLiveness\", () => {\n cb();\n });\n }\n listenToLookStraight(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"lookStraight\", () => {\n cb();\n });\n }\n listenToPlaceFace(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"placeFace\", () => {\n cb();\n });\n }\n listenToFaceTooFar(cb) {\n var _a;\n (_a = this.overlayElement) === null || _a === void 0 ? void 0 : _a.addEventListener(\"faceTooFar\", () => {\n cb();\n });\n }\n}\nexports[\"default\"] = FACEDETECTIONSDK;\n\n\n//# sourceURL=webpack://PWUISDK/./src/plugins/face-detection.ts?");
4048
4048
 
4049
4049
  /***/ }),
4050
4050
 
@@ -4055,7 +4055,7 @@ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _argument
4055
4055
  /***/ ((__unused_webpack_module, exports) => {
4056
4056
 
4057
4057
  "use strict";
4058
- eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports[\"default\"] = {\n // btn\n btn_start_now: \"Start Now\",\n btn_continue_on_mobile: \"Continue on Mobile\",\n btn_close: \"Close\",\n btn_okay: \"Okay\",\n btn_retake: \"Retake\",\n btn_proceed: \"Proceed\",\n btn_try_again: \"Try Again\",\n btn_submit: \"Submit\",\n btn_done: \"Done\",\n btn_capture_now: \"Capture now\",\n // common\n loading: \"Loading\",\n loading_dots: \"Loading...\",\n search: \"Search\",\n type_to_search: \"Type to search\",\n no_result_found: \"No result found\",\n // qr code dialog\n qr_dialog_title: \"Continue verification on mobile\",\n qr_instruction: \"Scan the QR code below using your mobile device to initiate the verification process.\",\n qr_browser_notice: \"Verification is supported only in Chrome, Firefox, and Safari (iOS). The WeChat QR Scanner is not supported.\",\n // first page\n national_identity_document_title: \"Capture ID photo\",\n national_identity_document_desc: \"Please ensure your document is clear, readable and valid.\",\n selfie_title: \"Face scan\",\n selfie_desc: \"Position your face in the frame and follow the instructions given. Do not wear sunglasses, hat or accessories. Background must be light and neutral.\",\n cc_title: \"Credit card verification\",\n cc_desc: \"\",\n poa_title: \"Utility bill verification\",\n poa_desc: \"Please ensure your document is clear, readable and valid.\",\n // national identity document\n select_id_type: \"Select ID type\",\n issuing_country: \"Issuing country/region\",\n document_type: \"Document type\",\n id_card: \"ID Card\",\n driver_license: \"Driver's License\",\n passport: \"Passport\",\n error_id_glare: \"The image has glare issues, please take a clear photo in a well-lit area.\",\n error_id_empty: \"No document detected in the image. Please ensure your document is clearly visible within the frame and properly lit.\",\n error_id_blur: \"The image is blurry. Please hold steady and take a clear photo.\",\n error_id_not_positioned: \"The document is not positioned properly. Please align it within the frame.\",\n error_id_unpair: \"The front and back images don't match. Please capture the same document.\",\n error_id_unsimilar: \"The front and back images appear to be from different documents.\",\n error_id_generic: \"Unable to verify the document. Please ensure it is clear, valid, and properly positioned.\",\n // selfie\n error_selfie: \"The image is blur, please take a clear photo.\",\n // credit card\n cc_missing_info_title: \"Missing card info.\",\n cc_missing_info_desc: \"Capture the side of the card with:\",\n // - cc_missing_content_* (dont change the id_key)\n cc_missing_content_full_name: \"Card owner's name\",\n cc_missing_content_cc_number: \"Card number\",\n cc_missing_content_cc_number_first_6: \"First 6 digits of card number\",\n cc_missing_content_cc_number_last_4: \"Last 4 digits of card number\",\n cc_missing_content_date_of_expiry: \"Expiry date\",\n cc_expired_with_retry: \"Credit card expired. Please provide a new card to continue.\",\n cc_expired_without_retry: \"Credit card expired. Please ensure your credit card is valid.\",\n error_cc_glare: \"The image has glare issues, please take a clear photo in a well-lit area.\",\n error_cc_empty: \"No card detected in the image. Please ensure your card is clearly visible within the frame and properly lit.\",\n error_cc_blur: \"The image is blurry. Please hold steady and take a clear photo.\",\n error_cc_generic: \"Unable to verify the card. Please ensure it is clear, valid, and properly positioned.\",\n // proof of address\n proof_of_address_title: \"Upload utility bill\",\n proof_of_address_desc: \"Please upload your utility bill\",\n image_format_label: \"Format: PNG, JPG, JPEG or PDF ({size}MB max)\",\n click_to_take_photo: \"Click to take photo\",\n poa_capture_or_choose: \"Capture or choose from gallery\",\n poa_doc_tip_title: \"Document tips:\",\n poa_doc_tip_1: \"Your name and address should be clearly visible.\",\n poa_doc_tip_2: \"Use PDF, JPEG, PNG files.\",\n poa_doc_tip_3: \"Max file size: 2MB.\",\n error_poa_file_missing: \"Please upload your utility bill to continue.\",\n error_poa_file_invalid: \"Only files in this extensions are allowed to be upload: PNG, JPG, JPEG or PDF ({size}MB max)\",\n error_poa_idle_long: \"The uploaded file is invalid due to you have been idle for too long.\",\n error_poa_file_generic: \"Unable to verify the document. Please ensure it is clear, valid, and properly uploaded.\",\n error_poa: \"Something went wrong. Please contact customer support for assistance or retry.\",\n // camera instruction\n id_front_title: \"ID Card | Front\",\n id_front_outline: \"Front of ID\",\n id_back_title: \"ID Card | Back\",\n id_back_outline: \"Back of ID\",\n license_front_title: \"License | Front\",\n license_back_title: \"License | Back\",\n passport_title: \"Passport\",\n cc_front_title: \"Credit Card\",\n cc_back_title: \"Credit Card\",\n camera_desc: \"Place your document within the frame and take photo.\",\n id_camera_dec: \"Please capture the front of your ID card, where your photo is visible. Ensure all details are clear.\",\n idle_message: \"You have been idle for too long.\",\n tips: \"Tips\",\n card: \"Card\",\n id_tip_1: \"Place your {cardType} within the frame and take picture.\",\n id_tip_2: \"Make sure the photo is not blur or cropped.\",\n id_tip_3: \"Avoid reflection and glare.\",\n selfie_tip_1: \"Position your face within the frame and follow the instructions given.\",\n selfie_tip_2: \"Make sure your face is not blur or cropped.\",\n selfie_tip_3: \"Do not wear sunglasses, hat or accessories.\",\n selfie_tip_4: \"Background must be light and neutral.\",\n cc_tip_title: \"Please show the info below:\",\n cc_tip_1: \"Card owner's name\",\n cc_tip_2: \"First 6 and last 4 digits ONLY\",\n cc_tip_3: \"Expiry date\",\n cc_tip_bottom_1: \"Some credit/debit cards may require capturing both front and back to obtain all mandatory information.\",\n cc_tip_bottom_2: \"You may cover the middle digits and CVV on the card manually or cover it later.\",\n flip_other_side: \"Flip the other side\",\n face_smile_at_camera: \"Please smile at the camera.\",\n face_smile_seconds: \"Please keep smiling for 3 seconds.\",\n face_neutral_expression: \"Please show a neutral expression at the camera.\",\n face_looks_straight: \"Please look straight at the camera.\",\n face_within_frame: \"Place your face within the rounded frame.\",\n card_masking_title: \"Hide your info\",\n card_masking_desc: \"Please cover the middle digits and CVV on the card.\",\n // submission limit\n submission_limit_title: \"Submission limit reached\",\n submission_limit_desc: \"Your submission couldn't be processed as it has reached the maximum number of attempts.\",\n // analyze page\n analyze_title: \"Analyzing the pictures\",\n analyze_desc: \"Please do not close your browser, this may take a moment.\",\n error_analyze: \"Unable to verify your documents. Please check your documents and resubmit again.\",\n verification_failed: \"Verification unsuccessful\",\n verification_failed_desc: \"Something went wrong while processing your document. Please contact customer support for assistance or retry.\",\n // summary\n review_verification_details: \"Review your verification details\",\n // - form label - label_* (dont change the id_key)\n label_full_name: \"Full name\",\n // - credit card\n label_cc_number: \"Card number\",\n label_cc_number_first_6: \"First 6 Card Number\",\n label_cc_number_last_4: \"Last 4 Card Number\",\n label_doe_year: \"Expiry date\",\n label_doe_month: \"Expiry date\",\n label_date_of_expiry: \"Expiry date\",\n // - national identity document\n label_given_name: \"Given name\",\n label_surname: \"Surname\",\n label_id_number: \"Identity card number\",\n label_date_of_birth: \"Date of birth\",\n label_gender: \"Gender\",\n label_line1: \"Address\",\n label_city: \"City\",\n label_zip: \"Zip code\",\n label_country_iso2: \"Country\",\n label_state_iso: \"State/Region\",\n // - proof of address\n label_receiver_name: \"Full Name\",\n label_receiver_address: \"Address\",\n label_receiver_city: \"City\",\n label_receiver_zip: \"Zip code\",\n label_receiver_country_iso2: \"Country\",\n label_receiver_state_iso: \"State/Region\",\n complete_verification: \"Complete verification\",\n // - images\n img_label_front: \"Front\",\n img_label_back: \"Back\",\n img_label_first: \"Capture 1\",\n img_label_second: \"Capture 2\",\n // complete page\n submission_received: \"Submission has been received\",\n count_down_message: \"Redirecting you to merchant page in {seconds} seconds.\",\n return_to_desktop_message: \"You can now return to your desktop to continue.\",\n // error page\n smtg_went_wrong: \"Something went wrong\",\n fail_to_locate_verification: \"We could not locate a suitable verification type for you. Please contact customer support for assistance.\",\n contact_support: \"Please contact customer support for assistance or retry.\",\n back_to_merchant: \"Back to merchant\",\n // error message - error_* (dont change the id_key)\n error_expiry_date: \"The expiry date must be today or in the future.\",\n error_invalid_month: \"Month must be between 1 and 12.\",\n error_required: \"This field is required.\",\n error_invalid_field: \"Invalid {field}.\",\n error_min_char: \"This field requires min {n} characters length.\",\n error_max_char: \"This field requires max {n} characters length.\",\n error_between_char: \"This field requires min {min} and max {max} characters length.\",\n error_invalid_card: \"This field requires first 6 and last 4 digits.\",\n};\n\n\n//# sourceURL=webpack://PWUISDK/./src/translations/en.ts?");
4058
+ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports[\"default\"] = {\n // btn\n btn_start_now: \"Start Now\",\n btn_continue_on_mobile: \"Continue on Mobile\",\n btn_close: \"Close\",\n btn_okay: \"Okay\",\n btn_retake: \"Retake\",\n btn_proceed: \"Proceed\",\n btn_try_again: \"Try Again\",\n btn_submit: \"Submit\",\n btn_done: \"Done\",\n btn_capture_now: \"Capture now\",\n // common\n loading: \"Loading\",\n loading_dots: \"Loading...\",\n search: \"Search\",\n type_to_search: \"Type to search\",\n no_result_found: \"No result found\",\n // qr code dialog\n qr_dialog_title: \"Continue verification on mobile\",\n qr_instruction: \"Scan the QR code below using your mobile device to initiate the verification process.\",\n qr_browser_notice: \"Verification is supported only in Chrome, Firefox, and Safari (iOS). The WeChat QR Scanner is not supported.\",\n // first page\n national_identity_document_title: \"Capture ID photo\",\n national_identity_document_desc: \"Please ensure your document is clear, readable and valid.\",\n selfie_title: \"Face scan\",\n selfie_desc: \"Position your face in the frame and follow the instructions given. Do not wear sunglasses, hat or accessories. Background must be light and neutral.\",\n cc_title: \"Credit card verification\",\n cc_desc: \"\",\n poa_title: \"Utility bill verification\",\n poa_desc: \"Please ensure your document is clear, readable and valid.\",\n // national identity document\n select_id_type: \"Select ID type\",\n issuing_country: \"Issuing country/region\",\n document_type: \"Document type\",\n id_card: \"ID Card\",\n driver_license: \"Driver's License\",\n passport: \"Passport\",\n error_id_glare: \"The image has glare issues, please take a clear photo in a well-lit area.\",\n error_id_empty: \"No document detected in the image. Please ensure your document is clearly visible within the frame and properly lit.\",\n error_id_blur: \"The image is blurry. Please hold steady and take a clear photo.\",\n error_id_not_positioned: \"The document is not positioned properly. Please align it within the frame.\",\n error_id_unpair: \"The front and back images don't match. Please capture the same document.\",\n error_id_unsimilar: \"The front and back images appear to be from different documents.\",\n error_id_generic: \"Unable to verify the document. Please ensure it is clear, valid, and properly positioned.\",\n // selfie\n error_selfie: \"The image is blur, please take a clear photo.\",\n // credit card\n cc_missing_info_title: \"Missing card info.\",\n cc_missing_info_desc: \"Capture the side of the card with:\",\n // - cc_missing_content_* (dont change the id_key)\n cc_missing_content_full_name: \"Card owner's name\",\n cc_missing_content_cc_number: \"Card number\",\n cc_missing_content_cc_number_first_6: \"First 6 digits of card number\",\n cc_missing_content_cc_number_last_4: \"Last 4 digits of card number\",\n cc_missing_content_date_of_expiry: \"Expiry date\",\n cc_expired_with_retry: \"Credit card expired. Please provide a new card to continue.\",\n cc_expired_without_retry: \"Credit card expired. Please ensure your credit card is valid.\",\n error_cc_glare: \"The image has glare issues, please take a clear photo in a well-lit area.\",\n error_cc_empty: \"No card detected in the image. Please ensure your card is clearly visible within the frame and properly lit.\",\n error_cc_blur: \"The image is blurry. Please hold steady and take a clear photo.\",\n error_cc_generic: \"Unable to verify the card. Please ensure it is clear, valid, and properly positioned.\",\n // proof of address\n proof_of_address_title: \"Upload utility bill\",\n proof_of_address_desc: \"Please upload your utility bill\",\n image_format_label: \"Format: PNG, JPG, JPEG or PDF ({size}MB max)\",\n click_to_take_photo: \"Click to take photo\",\n poa_capture_or_choose: \"Capture or choose from gallery\",\n poa_doc_tip_title: \"Document tips:\",\n poa_doc_tip_1: \"Your name and address should be clearly visible.\",\n poa_doc_tip_2: \"Use PDF, JPEG, PNG files.\",\n poa_doc_tip_3: \"Max file size: 2MB.\",\n error_poa_file_missing: \"Please upload your utility bill to continue.\",\n error_poa_file_invalid: \"Only files in this extensions are allowed to be upload: PNG, JPG, JPEG or PDF ({size}MB max)\",\n error_poa_idle_long: \"The uploaded file is invalid due to you have been idle for too long.\",\n error_poa_file_generic: \"Unable to verify the document. Please ensure it is clear, valid, and properly uploaded.\",\n error_poa: \"Something went wrong. Please contact customer support for assistance or retry.\",\n // camera instruction\n id_front_title: \"ID Card | Front\",\n id_front_outline: \"Front of ID\",\n id_back_title: \"ID Card | Back\",\n id_back_outline: \"Back of ID\",\n license_front_title: \"License | Front\",\n license_back_title: \"License | Back\",\n passport_title: \"Passport\",\n cc_front_title: \"Credit Card\",\n cc_back_title: \"Credit Card\",\n camera_desc: \"Place your document within the frame and take photo.\",\n id_camera_dec: \"Please capture the front of your ID card, where your photo is visible. Ensure all details are clear.\",\n idle_message: \"You have been idle for too long.\",\n tips: \"Tips\",\n card: \"Card\",\n id_tip_1: \"Place your {cardType} within the frame and take picture.\",\n id_tip_2: \"Make sure the photo is not blur or cropped.\",\n id_tip_3: \"Avoid reflection and glare.\",\n selfie_tip_1: \"Position your face within the frame and follow the instructions given.\",\n selfie_tip_2: \"Make sure your face is not blur or cropped.\",\n selfie_tip_3: \"Do not wear sunglasses, hat or accessories.\",\n selfie_tip_4: \"Background must be light and neutral.\",\n cc_tip_title: \"Please show the info below:\",\n cc_tip_1: \"Card owner's name\",\n cc_tip_2: \"First 6 and last 4 digits ONLY\",\n cc_tip_3: \"Expiry date\",\n cc_tip_bottom_1: \"Some credit/debit cards may require capturing both front and back to obtain all mandatory information.\",\n cc_tip_bottom_2: \"You may cover the middle digits and CVV on the card manually or cover it later.\",\n flip_other_side: \"Flip the other side\",\n face_smile_at_camera: \"Please smile at the camera.\",\n face_smile_seconds: \"Please keep smiling for 3 seconds.\",\n face_neutral_expression: \"Please show a neutral expression at the camera.\",\n face_looks_straight: \"Please look straight at the camera.\",\n face_within_frame: \"Place your face within the rounded frame.\",\n face_too_far: \"Move closer to the camera.\",\n card_masking_title: \"Hide your info\",\n card_masking_desc: \"Please cover the middle digits and CVV on the card.\",\n // submission limit\n submission_limit_title: \"Submission limit reached\",\n submission_limit_desc: \"Your submission couldn't be processed as it has reached the maximum number of attempts.\",\n // analyze page\n analyze_title: \"Analyzing the pictures\",\n analyze_desc: \"Please do not close your browser, this may take a moment.\",\n error_analyze: \"Unable to verify your documents. Please check your documents and resubmit again.\",\n verification_failed: \"Verification unsuccessful\",\n verification_failed_desc: \"Something went wrong while processing your document. Please contact customer support for assistance or retry.\",\n // summary\n review_verification_details: \"Review your verification details\",\n // - form label - label_* (dont change the id_key)\n label_full_name: \"Full name\",\n // - credit card\n label_cc_number: \"Card number\",\n label_cc_number_first_6: \"First 6 Card Number\",\n label_cc_number_last_4: \"Last 4 Card Number\",\n label_doe_year: \"Expiry date\",\n label_doe_month: \"Expiry date\",\n label_date_of_expiry: \"Expiry date\",\n // - national identity document\n label_given_name: \"Given name\",\n label_surname: \"Surname\",\n label_id_number: \"Identity card number\",\n label_date_of_birth: \"Date of birth\",\n label_gender: \"Gender\",\n label_line1: \"Address\",\n label_city: \"City\",\n label_zip: \"Zip code\",\n label_country_iso2: \"Country\",\n label_state_iso: \"State/Region\",\n // - proof of address\n label_receiver_name: \"Full Name\",\n label_receiver_address: \"Address\",\n label_receiver_city: \"City\",\n label_receiver_zip: \"Zip code\",\n label_receiver_country_iso2: \"Country\",\n label_receiver_state_iso: \"State/Region\",\n complete_verification: \"Complete verification\",\n // - images\n img_label_front: \"Front\",\n img_label_back: \"Back\",\n img_label_first: \"Capture 1\",\n img_label_second: \"Capture 2\",\n // complete page\n submission_received: \"Submission has been received\",\n count_down_message: \"Redirecting you to merchant page in {seconds} seconds.\",\n return_to_desktop_message: \"You can now return to your desktop to continue.\",\n // error page\n smtg_went_wrong: \"Something went wrong\",\n fail_to_locate_verification: \"We could not locate a suitable verification type for you. Please contact customer support for assistance.\",\n contact_support: \"Please contact customer support for assistance or retry.\",\n back_to_merchant: \"Back to merchant\",\n // error message - error_* (dont change the id_key)\n error_expiry_date: \"The expiry date must be today or in the future.\",\n error_invalid_month: \"Month must be between 1 and 12.\",\n error_required: \"This field is required.\",\n error_invalid_field: \"Invalid {field}.\",\n error_min_char: \"This field requires min {n} characters length.\",\n error_max_char: \"This field requires max {n} characters length.\",\n error_between_char: \"This field requires min {min} and max {max} characters length.\",\n error_invalid_card: \"This field requires first 6 and last 4 digits.\",\n};\n\n\n//# sourceURL=webpack://PWUISDK/./src/translations/en.ts?");
4059
4059
 
4060
4060
  /***/ }),
4061
4061
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipwave-ekyc-uikit",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "",
5
5
  "main": "dist/pw-bundle.js",
6
6
  "scripts": {
@@ -30,8 +30,7 @@
30
30
  "webpack-dev-server": "^4.15.1"
31
31
  },
32
32
  "dependencies": {
33
- "@tensorflow/tfjs-node": "^4.9.0",
34
- "@types/pdfjs-dist": "^2.10.378",
33
+ "@types/pdfjs-dist": "^2.10.378",
35
34
  "@types/w3c-image-capture": "^1.0.7",
36
35
  "dotenv": "^16.3.1",
37
36
  "dotenv-webpack": "^8.0.1",