@concordium/verification-web-ui 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/assets/appstore-icon.svg.js +5 -0
- package/dist/assets/appstore-icon.svg.js.map +1 -0
- package/dist/assets/playstore-icon.svg.js +5 -0
- package/dist/assets/playstore-icon.svg.js.map +1 -0
- package/dist/components/desktop/landing.js +122 -5
- package/dist/components/desktop/landing.js.map +1 -1
- package/dist/components/desktop/processing.js +6 -1
- package/dist/components/desktop/processing.js.map +1 -1
- package/dist/components/desktop/returning-user.js +3 -2
- package/dist/components/desktop/returning-user.js.map +1 -1
- package/dist/components/desktop/scan.d.ts +6 -3
- package/dist/components/desktop/scan.js +116 -12
- package/dist/components/desktop/scan.js.map +1 -1
- package/dist/components/desktop/wallet-selection.d.ts +20 -0
- package/dist/components/desktop/wallet-selection.js +423 -0
- package/dist/components/desktop/wallet-selection.js.map +1 -0
- package/dist/constants/modal.constants.d.ts +2 -0
- package/dist/constants/modal.constants.js +3 -1
- package/dist/constants/modal.constants.js.map +1 -1
- package/dist/constants/popup.constants.d.ts +2 -2
- package/dist/constants/wallet.registry.d.ts +61 -0
- package/dist/constants/wallet.registry.js +129 -0
- package/dist/constants/wallet.registry.js.map +1 -0
- package/dist/constants/walletconnect.constants.d.ts +3 -0
- package/dist/constants/walletconnect.constants.js +14 -1
- package/dist/constants/walletconnect.constants.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.js +52 -10
- package/dist/sdk.js.map +1 -1
- package/dist/services/walletconnect.service.d.ts +10 -0
- package/dist/services/walletconnect.service.js +34 -0
- package/dist/services/walletconnect.service.js.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/utils/mobileAppDetection.d.ts +13 -0
- package/dist/utils/mobileAppDetection.js +7 -3
- package/dist/utils/mobileAppDetection.js.map +1 -1
- package/dist/verification-web-ui.css +1 -1
- package/package.json +1 -1
|
@@ -47,8 +47,8 @@ function createDesktopScanHTML() {
|
|
|
47
47
|
</div>
|
|
48
48
|
</div>
|
|
49
49
|
|
|
50
|
-
<div id="qr-container" class="${CSS_CLASSES.FLEX} items-center justify-center min-
|
|
51
|
-
<div class="animate-pulse text-center">
|
|
50
|
+
<div id="qr-container" class="${CSS_CLASSES.FLEX} items-center justify-center" style="min-height: 380px;">
|
|
51
|
+
<div class="animate-pulse text-center" style="display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
52
52
|
<div class="w-48 h-48 bg-gray-200 rounded mb-2"></div>
|
|
53
53
|
<p class="text-sm" style="color: #0D0F11;">Generating QR code...</p>
|
|
54
54
|
</div>
|
|
@@ -285,11 +285,14 @@ async function initializeSDKManagedConnection() {
|
|
|
285
285
|
}
|
|
286
286
|
const wcService = ServiceFactory.createWalletConnectService();
|
|
287
287
|
await wcService.initialize();
|
|
288
|
+
await wcService.clearAllSessionsForNewPairing();
|
|
288
289
|
const { WalletConnectConstants } = await import("../../constants/walletconnect.constants.js");
|
|
289
290
|
const chainIds = WalletConnectConstants.CHAIN_IDS[network];
|
|
290
291
|
const { uri, approval } = await wcService.connect({
|
|
291
292
|
ccd: {
|
|
292
|
-
methods
|
|
293
|
+
// Request all methods for broad wallet compatibility
|
|
294
|
+
// This allows both ID App (v1) and Concordium Wallet (v0) to connect
|
|
295
|
+
methods: [...WalletConnectConstants.ALL_METHODS],
|
|
293
296
|
chains: chainIds,
|
|
294
297
|
events: [...WalletConnectConstants.EVENTS]
|
|
295
298
|
}
|
|
@@ -334,14 +337,106 @@ async function initializeMerchantProvidedConnection() {
|
|
|
334
337
|
await displayQRCode(storedUri);
|
|
335
338
|
}
|
|
336
339
|
}
|
|
340
|
+
async function autoSendPresentationRequestIfConfigured(topic) {
|
|
341
|
+
try {
|
|
342
|
+
const presentationRequestStr = localStorage.getItem(
|
|
343
|
+
ModalConstants.LOCAL_STORAGE_FLAGS.SDK_PRESENTATION_REQUEST
|
|
344
|
+
);
|
|
345
|
+
if (!presentationRequestStr) {
|
|
346
|
+
console.log("No presentation request configured, waiting for merchant to send request");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const presentationRequest = JSON.parse(presentationRequestStr);
|
|
350
|
+
console.log("Auto-sending presentation request:", presentationRequest);
|
|
351
|
+
const wcService = ServiceFactory.getWalletConnectService();
|
|
352
|
+
if (!wcService) {
|
|
353
|
+
console.error("WalletConnect service not available for auto-send");
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK);
|
|
357
|
+
const chainId = network === "mainnet" ? "ccd:9dd9ca4d19e9393877d2c44b70f89acb" : "ccd:4221332d34e1694168c2a0c0b3fd0f27";
|
|
358
|
+
const metadataStr = localStorage.getItem("sdkWalletConnectMetadata");
|
|
359
|
+
const storedMetadata = metadataStr ? JSON.parse(metadataStr) : {};
|
|
360
|
+
const metadata = {
|
|
361
|
+
description: storedMetadata?.description || "Requesting verification",
|
|
362
|
+
appName: storedMetadata?.name || "Concordium Verification WebUI",
|
|
363
|
+
url: storedMetadata?.url || window.location.origin,
|
|
364
|
+
icons: storedMetadata?.icons || []
|
|
365
|
+
};
|
|
366
|
+
let response;
|
|
367
|
+
let methodUsed;
|
|
368
|
+
try {
|
|
369
|
+
console.log("Trying v1 method (request_verifiable_presentation_v1)...");
|
|
370
|
+
response = await wcService.request({
|
|
371
|
+
topic,
|
|
372
|
+
chainId,
|
|
373
|
+
request: {
|
|
374
|
+
method: "request_verifiable_presentation_v1",
|
|
375
|
+
params: {
|
|
376
|
+
...presentationRequest,
|
|
377
|
+
metadata
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
methodUsed = "v1";
|
|
382
|
+
} catch (v1Error) {
|
|
383
|
+
console.log("v1 method failed, trying v0 method...", v1Error);
|
|
384
|
+
response = await wcService.request({
|
|
385
|
+
topic,
|
|
386
|
+
chainId,
|
|
387
|
+
request: {
|
|
388
|
+
method: "request_verifiable_presentation",
|
|
389
|
+
params: {
|
|
390
|
+
...presentationRequest,
|
|
391
|
+
metadata
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
methodUsed = "v0";
|
|
396
|
+
}
|
|
397
|
+
console.log(`Presentation response received (method ${methodUsed}):`, response);
|
|
398
|
+
window.dispatchEvent(
|
|
399
|
+
new CustomEvent("verification-web-ui-event", {
|
|
400
|
+
detail: {
|
|
401
|
+
type: "presentation_received",
|
|
402
|
+
data: response
|
|
403
|
+
},
|
|
404
|
+
bubbles: true,
|
|
405
|
+
composed: true
|
|
406
|
+
})
|
|
407
|
+
);
|
|
408
|
+
const { showSuccessState } = await import("./processing.js");
|
|
409
|
+
await showSuccessState();
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.error("Failed to auto-send presentation request:", error);
|
|
412
|
+
window.dispatchEvent(
|
|
413
|
+
new CustomEvent("verification-web-ui-event", {
|
|
414
|
+
detail: {
|
|
415
|
+
type: "error",
|
|
416
|
+
data: {
|
|
417
|
+
message: "Failed to send verification request",
|
|
418
|
+
error
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
bubbles: true,
|
|
422
|
+
composed: true
|
|
423
|
+
})
|
|
424
|
+
);
|
|
425
|
+
const { showErrorState } = await import("./processing.js");
|
|
426
|
+
await showErrorState();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
337
429
|
async function handleSessionApproval(sessionData) {
|
|
338
430
|
try {
|
|
339
431
|
const { topic, namespaces } = sessionData;
|
|
340
432
|
const accounts = namespaces?.ccd?.accounts || [];
|
|
433
|
+
const walletName = sessionData.peer?.metadata?.name || "Wallet";
|
|
434
|
+
localStorage.setItem(ModalConstants.LOCAL_STORAGE_FLAGS.CONNECTED_WALLET_NAME, walletName);
|
|
341
435
|
const sessionEvent = {
|
|
342
436
|
topic,
|
|
343
437
|
accounts,
|
|
344
|
-
namespaces
|
|
438
|
+
namespaces,
|
|
439
|
+
walletName
|
|
345
440
|
};
|
|
346
441
|
window.dispatchEvent(
|
|
347
442
|
new CustomEvent("verification-web-ui-event", {
|
|
@@ -355,6 +450,7 @@ async function handleSessionApproval(sessionData) {
|
|
|
355
450
|
);
|
|
356
451
|
const { showProcessingModal } = await import("./processing.js");
|
|
357
452
|
await showProcessingModal();
|
|
453
|
+
await autoSendPresentationRequestIfConfigured(topic);
|
|
358
454
|
} catch (error) {
|
|
359
455
|
console.error("Error handling session approval:", error);
|
|
360
456
|
window.dispatchEvent(
|
|
@@ -377,24 +473,29 @@ async function displayQRCode(uri) {
|
|
|
377
473
|
try {
|
|
378
474
|
const { default: QRCode } = await import("qrcode");
|
|
379
475
|
const { getConfig } = await import("../../config.state.js");
|
|
476
|
+
const { getConcordiumIdDeepLink } = await import("../../constants/wallet.registry.js");
|
|
380
477
|
const config = getConfig();
|
|
381
478
|
const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);
|
|
382
479
|
if (qrContainer) {
|
|
383
|
-
const
|
|
480
|
+
const qrValue = getConcordiumIdDeepLink(uri);
|
|
481
|
+
console.log("Generated QR code value:", qrValue);
|
|
482
|
+
const qrCodeDataURL = await QRCode.toDataURL(qrValue, {
|
|
384
483
|
width: 200,
|
|
385
484
|
margin: 2,
|
|
386
485
|
color: { dark: "#000000", light: "#ffffff" }
|
|
387
486
|
});
|
|
388
487
|
const showCountdown = config.qrCode?.showCountdown !== false;
|
|
389
488
|
const countdownHTML = showCountdown ? '<p id="qr-countdown" class="text-sm text-inverse-tertiary mt-2">Expires in: <span class="font-semibold">5:00</span></p>' : "";
|
|
489
|
+
const { getIdAppStoreUrl } = await import("../../constants/wallet.registry.js");
|
|
490
|
+
const appStoreUrl = getIdAppStoreUrl();
|
|
390
491
|
qrContainer.innerHTML = `
|
|
391
|
-
<div class="text-center">
|
|
492
|
+
<div class="text-center" style="min-height: 350px; display: flex; flex-direction: column; justify-content: center;">
|
|
392
493
|
<img src="${qrCodeDataURL}" alt="QR Code for wallet connection" class="w-48 h-48 mx-auto mb-2" style="border-radius: 12.414px; border: 1px solid rgba(0, 0, 0, 0.10); background: #FFF;" />
|
|
393
494
|
<p class="desktop--scan-text mt-2">Scan the QR code with your<br>Concordium ID compatible device</p>
|
|
394
495
|
${countdownHTML}
|
|
395
496
|
<img src="${sectionSeparator}" alt="" class="mx-auto mt-4" />
|
|
396
497
|
<div class="flex items-center justify-center mt-4">
|
|
397
|
-
<p class="desktop--download-text">Download & Install the <a href="
|
|
498
|
+
<p class="desktop--download-text">Download & Install the <a href="${appStoreUrl}" target="_blank" rel="noopener noreferrer">Concordium ID App</a> and come back here to verify.</p>
|
|
398
499
|
</div>
|
|
399
500
|
</div>
|
|
400
501
|
`;
|
|
@@ -486,7 +587,7 @@ function showQRExpiredMessage(canRefresh) {
|
|
|
486
587
|
Refresh QR Code
|
|
487
588
|
</button>` : `<p class="text-sm text-inverse-tertiary mt-2">Waiting for new QR code from merchant...</p>`;
|
|
488
589
|
qrContainer.innerHTML = `
|
|
489
|
-
<div class="text-center">
|
|
590
|
+
<div class="text-center" style="min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
490
591
|
<div class="w-48 h-48 bg-yellow-50 border-2 border-yellow-200 rounded flex items-center justify-center mx-auto mb-2">
|
|
491
592
|
<svg class="w-16 h-16 text-yellow-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
492
593
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
@@ -511,7 +612,7 @@ function showQRRefreshing() {
|
|
|
511
612
|
const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);
|
|
512
613
|
if (qrContainer) {
|
|
513
614
|
qrContainer.innerHTML = `
|
|
514
|
-
<div class="animate-pulse text-center">
|
|
615
|
+
<div class="animate-pulse text-center" style="min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
515
616
|
<div class="w-48 h-48 bg-gray-200 rounded mb-2 mx-auto"></div>
|
|
516
617
|
<p class="text-sm text-inverse-tertiary">Refreshing QR code...</p>
|
|
517
618
|
</div>
|
|
@@ -534,7 +635,7 @@ function showQRError(message) {
|
|
|
534
635
|
const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);
|
|
535
636
|
if (qrContainer) {
|
|
536
637
|
qrContainer.innerHTML = `
|
|
537
|
-
<div class="text-center">
|
|
638
|
+
<div class="text-center" style="min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
538
639
|
<div class="w-48 h-48 bg-red-50 border-2 border-red-200 rounded flex items-center justify-center mx-auto mb-2">
|
|
539
640
|
<svg class="w-16 h-16 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
540
641
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
|
@@ -550,7 +651,7 @@ function showQRError(message) {
|
|
|
550
651
|
if (retryBtn) {
|
|
551
652
|
retryBtn.addEventListener("click", async () => {
|
|
552
653
|
qrContainer.innerHTML = `
|
|
553
|
-
<div class="animate-pulse text-center">
|
|
654
|
+
<div class="animate-pulse text-center" style="min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
554
655
|
<div class="w-48 h-48 bg-gray-200 rounded mb-2 mx-auto"></div>
|
|
555
656
|
<p class="text-sm text-inverse-tertiary">Generating QR code...</p>
|
|
556
657
|
</div>
|
|
@@ -614,7 +715,9 @@ function generateDeepLink(walletType, uri) {
|
|
|
614
715
|
async function displayQRCodeMobile(uri, container) {
|
|
615
716
|
try {
|
|
616
717
|
const { default: QRCode } = await import("qrcode");
|
|
617
|
-
const
|
|
718
|
+
const { buildQrRedirectUrl } = await import("../../constants/wallet.registry.js");
|
|
719
|
+
const qrValue = buildQrRedirectUrl(uri);
|
|
720
|
+
const qrCodeDataURL = await QRCode.toDataURL(qrValue, {
|
|
618
721
|
width: 200,
|
|
619
722
|
margin: 2,
|
|
620
723
|
color: { dark: "#000000", light: "#ffffff" }
|
|
@@ -636,6 +739,7 @@ async function displayQRCodeMobile(uri, container) {
|
|
|
636
739
|
}
|
|
637
740
|
}
|
|
638
741
|
export {
|
|
742
|
+
autoSendPresentationRequestIfConfigured,
|
|
639
743
|
createScanModal,
|
|
640
744
|
handleSessionApproval,
|
|
641
745
|
hideScanModal,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sources":["../../../src/components/desktop/scan.ts"],"sourcesContent":["// scan.ts - Scan Modal Implementation\nimport arrowLeft from '@/assets/arrow-left.svg';\nimport arrowRight from '@/assets/arrow-right.svg';\nimport concordiumModalLogo from '@/assets/concordium-modal-logo.svg';\nimport sectionSeparator from '@/assets/section-separator.svg';\nimport { isMobileScreen } from '@/config.state';\nimport { ModalConstants } from '@/constants/modal.constants';\nimport { dispatchConcordiumEvent } from '@/index';\nimport { ServiceFactory } from '@/services';\nimport type { HideModalFunction, ModalFunction, ShowModalFunction } from '@/types';\n\n// Global variables for modal state management\nlet scanModalElement: HTMLElement | null = null;\nlet processingTimeout: ReturnType<typeof setTimeout> | null = null;\nlet qrExpiryTimer: ReturnType<typeof setTimeout> | null = null;\nlet qrCountdownInterval: ReturnType<typeof setInterval> | null = null;\nlet currentQRCodeUri: string | null = null;\nlet currentSelectedWallet: WalletTypeValues;\n\n// Constants\nconst WALLET_TYPES = {\n CONCORDIUM_WALLET: 'concordium-wallet',\n BROWSER_WALLET: 'browser-wallet',\n CONCORDIUM_ID: 'concordium-id',\n} as const;\n\n// Initialize after WALLET_TYPES is defined\ncurrentSelectedWallet = WALLET_TYPES.CONCORDIUM_ID;\n\ntype WalletTypeKeys = keyof typeof WALLET_TYPES;\ntype WalletTypeValues = (typeof WALLET_TYPES)[WalletTypeKeys];\n\nconst CSS_CLASSES = {\n HIDDEN: 'hidden',\n FLEX: 'flex',\n FLEX_COL: 'flex-col',\n} as const;\n\nconst SELECTORS = {\n APP: '#app',\n SCAN_MODAL: '#scan-modal',\n BACK_BTN: '#back-btn',\n QR_CONTAINER: '#qr-container',\n BROWSER_BTN: '#browser-btn',\n BROWSER_WALLET_BTN: '#browser-wallet-btn',\n} as const;\n\n// Helper function to create desktop HTML\nfunction createDesktopScanHTML(): string {\n return `\n <div class=\"desktop--modal-overlay\">\n <div class=\"desktop--modal-container\">\n <div class=\"desktop--modal-body\">\n <div class=\"flex items-center justify-between p-2\">\n <button class=\"desktop--navigation-button\" id=\"back-btn\">\n <img src=\"${arrowLeft}\" alt=\"arrow-left-icon\" />\n <span>Back</span>\n </button>\n <div>\n <img src=\"${concordiumModalLogo}\" alt=\"concordium-modal-logo\" />\n </div>\n </div>\n\n <div id=\"qr-container\" class=\"${CSS_CLASSES.FLEX} items-center justify-center min-h-[200px]\">\n <div class=\"animate-pulse text-center\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2\"></div>\n <p class=\"text-sm\" style=\"color: #0D0F11;\">Generating QR code...</p>\n </div>\n </div>\n\n <div id=\"browser-btn\" class=\"${CSS_CLASSES.HIDDEN} ${CSS_CLASSES.FLEX_COL} items-center gap-4\">\n <button class=\"desktop--primary-button\" id=\"browser-wallet-btn\">\n <span>Verify with Browser Wallet</span>\n <img src=\"${arrowRight}\" alt=\"arrow-right-icon\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n `;\n}\n\n// Helper function to create mobile HTML\nfunction createMobileScanHTML(): string {\n return `\n <div class=\"mobile--modal-overlay position-relative\">\n <div class=\"mobile--modal-container\">\n <div class=\"mobile--modal-body\">\n <div class=\"flex items-center justify-between p-2\">\n <button class=\"mobile--navigation-button\" id=\"back-btn\">\n <img src=\"${arrowLeft}\" alt=\"arrow-left-icon\" />\n <span>Back</span>\n </button>\n <div>\n <img src=\"${concordiumModalLogo}\" alt=\"concordium-modal-logo\" />\n </div>\n </div>\n\n <div id=\"mobile-loading\" class=\"${CSS_CLASSES.FLEX} items-center justify-center min-h-[300px]\">\n <div class=\"animate-pulse text-center\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2 mx-auto\"></div>\n <p class=\"text-sm\" style=\"color: #0D0F11;\">Preparing wallet connection...</p>\n </div>\n </div>\n\n <div id=\"mobile-content\" class=\"${CSS_CLASSES.HIDDEN}\">\n <div id=\"btn-wrapper\" class=\"flex flex-col w-full items-center gap-2 mt-4\">\n <button class=\"mobile--primary-button w-full\" id=\"open-in-wallet-btn\">\n <span id=\"wallet-btn-text\">Verify with ConcordiumID</span>\n <img src=\"${arrowRight}\" alt=\"arrow-right-icon\" />\n </button>\n <button class=\"mobile--primary-outline-button w-full\" id=\"open-other-device-btn\">\n <span>Verify on Another Device</span>\n </button>\n </div>\n\n <div id=\"qr-container\" class=\"${CSS_CLASSES.HIDDEN}\" style=\"display: none;\">\n <!-- QR code will be generated here when user clicks \"Verify on Another Device\" -->\n </div>\n </div>\n </div>\n </div>\n </div>\n `;\n}\n\nexport const createScanModal: ModalFunction = () => {\n // Detect if mobile screen\n const isMobile = isMobileScreen();\n\n const scanHTML = isMobile ? createMobileScanHTML() : createDesktopScanHTML();\n\n const scanContainer = document.createElement('div');\n scanContainer.innerHTML = scanHTML;\n scanContainer.id = 'scan-modal';\n\n // Cache DOM elements for better performance\n const elements = {\n backBtn: scanContainer.querySelector(SELECTORS.BACK_BTN) as HTMLButtonElement | null,\n browserWalletBtn: scanContainer.querySelector(SELECTORS.BROWSER_WALLET_BTN) as HTMLButtonElement | null,\n openInWalletBtn: scanContainer.querySelector('#open-in-wallet-btn') as HTMLButtonElement | null,\n openOtherDeviceBtn: scanContainer.querySelector('#open-other-device-btn') as HTMLButtonElement | null,\n qrContainer: scanContainer.querySelector(SELECTORS.QR_CONTAINER) as HTMLElement | null,\n };\n\n // Event handlers following your modal navigation pattern\n const handleBack = async (): Promise<void> => {\n const { showLandingModal } = await import('./landing');\n hideScanModal();\n await showLandingModal();\n };\n\n const handleBrowserWallet = async (): Promise<void> => {\n // Processing modal will be shown automatically after session approval\n // Don't hide scan modal - keep it visible until session is established\n };\n\n // Mobile-specific handlers\n const handleOpenInWallet = async (): Promise<void> => {\n try {\n // Check if URI is available\n if (!currentQRCodeUri) {\n const storedUri = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.WALLET_CONNECT_URI);\n if (storedUri) {\n currentQRCodeUri = storedUri;\n } else {\n await initializeWalletConnection();\n if (!currentQRCodeUri) {\n alert('Connection URI not available. Please refresh and try again.');\n return;\n }\n }\n }\n\n // Determine app type based on selection\n const appType =\n currentSelectedWallet === WALLET_TYPES.CONCORDIUM_ID ? 'concordium-id' : 'concordium-wallet';\n\n // Generate and open deep link directly (simpler approach)\n const deepLink = generateDeepLink(currentSelectedWallet, currentQRCodeUri!);\n\n if (deepLink) {\n window.location.href = deepLink;\n } else {\n // Fallback: try to open app store\n const { openAppStore } = await import('@/utils/mobileAppDetection');\n openAppStore(appType);\n }\n } catch (error) {\n console.error('[Mobile] handleOpenInWallet failed:', error);\n alert('Failed to open wallet app. Please try again.');\n }\n };\n\n const handleOpenOtherDevice = async (): Promise<void> => {\n const btnWrapper = scanContainer.querySelector('#btn-wrapper');\n if (btnWrapper) {\n btnWrapper.classList.add(CSS_CLASSES.HIDDEN);\n }\n\n if (currentQRCodeUri && elements.qrContainer) {\n await displayQRCodeMobile(currentQRCodeUri, elements.qrContainer);\n }\n };\n\n // Attach event listeners with null safety\n elements.backBtn?.addEventListener('click', handleBack);\n elements.browserWalletBtn?.addEventListener('click', handleBrowserWallet);\n\n // Mobile-specific event listeners\n if (isMobile) {\n elements.openInWalletBtn?.addEventListener('click', handleOpenInWallet);\n elements.openOtherDeviceBtn?.addEventListener('click', handleOpenOtherDevice);\n }\n\n return scanContainer;\n};\n\nexport const showScanModal: ShowModalFunction = async () => {\n const { getGlobalContainer } = await import('../../index');\n const targetContainer = getGlobalContainer();\n\n if (!targetContainer) {\n console.error('Container not found for modal');\n return;\n }\n\n // Detect mobile/desktop mode\n const isMobile = isMobileScreen();\n const containerClass = isMobile ? '.mobile--modal-container' : '.desktop--modal-container';\n\n // Create and store modal element reference\n scanModalElement = createScanModal();\n scanModalElement.id = 'scan-modal';\n\n // Get the modal container for transforms\n const modalContainer = scanModalElement.querySelector(containerClass) as HTMLElement | null;\n\n // For smooth transitions, prepare new modal completely before showing\n scanModalElement.style.opacity = '0';\n if (modalContainer) {\n modalContainer.style.transform = 'translateY(-20px) scale(0.95)';\n modalContainer.style.transition = 'transform 0.3s ease-out';\n }\n targetContainer.appendChild(scanModalElement);\n\n // Force a reflow to ensure the styles are applied\n scanModalElement.offsetHeight;\n\n // Now start the transition\n scanModalElement.style.transition = 'opacity 0.3s ease-out';\n\n // Use a small delay to ensure DOM is fully ready\n setTimeout(() => {\n // Check if modal still exists (may have been removed by active session detection)\n if (!scanModalElement) {\n return;\n }\n\n // Show new modal\n scanModalElement.style.opacity = '1';\n if (modalContainer) {\n modalContainer.style.transform = 'translateY(0) scale(1)';\n }\n }, 10);\n\n // Set up event listeners for session approval and verification completion\n setupEventListeners();\n\n // Initialize WalletConnect after modal is mounted\n await initializeWalletConnection();\n};\n\nexport const hideScanModal: HideModalFunction = () => {\n if (scanModalElement) {\n // Clean up dropdown instance following your cleanup pattern\n if ((scanModalElement as any).dropdownInstance?.destroy) {\n (scanModalElement as any).dropdownInstance.destroy();\n }\n\n // Add fade-out animation\n scanModalElement.classList.add('modal-exiting');\n\n // Remove from DOM after animation completes\n setTimeout(() => {\n const container = scanModalElement?.parentNode;\n if (container && scanModalElement) {\n container.removeChild(scanModalElement);\n }\n scanModalElement = null;\n // Restore body overflow if no other modals are present\n if (\n !document.querySelector('.desktop--modal-overlay') &&\n !document.querySelector('.mobile--modal-overlay')\n ) {\n document.body.style.overflowX = '';\n }\n }, 300);\n }\n\n // Clear any active timers\n if (processingTimeout) {\n clearTimeout(processingTimeout);\n processingTimeout = null;\n }\n\n // Clear QR code expiry timers\n if (qrExpiryTimer) {\n clearTimeout(qrExpiryTimer);\n qrExpiryTimer = null;\n }\n\n if (qrCountdownInterval) {\n clearInterval(qrCountdownInterval);\n qrCountdownInterval = null;\n }\n\n // Clean up event listeners following your cleanup pattern\n if ((window as any).scanEventCleanup) {\n (window as any).scanEventCleanup();\n (window as any).scanEventCleanup = null;\n }\n\n // Clean up custom event listeners\n if ((window as any).scanEventListeners) {\n (window as any).scanEventListeners.forEach((cleanup: () => void) => cleanup());\n (window as any).scanEventListeners = null;\n }\n};\n\n// WalletConnect initialization function\nasync function initializeWalletConnection(): Promise<void> {\n try {\n // Check connection mode to determine how to handle WalletConnect\n const connectionMode = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.CONNECTION_MODE);\n\n // Set up WalletConnect config early if in SDK-managed mode\n if (connectionMode === 'sdk-managed') {\n const projectId = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_PROJECT_ID);\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK);\n const metadataStr = localStorage.getItem('sdkWalletConnectMetadata');\n const metadata = metadataStr ? JSON.parse(metadataStr) : null;\n\n if (projectId && network) {\n // Store the config globally so ServiceFactory can use it\n (window as any).__CONCORDIUM_WC_CONFIG__ = {\n projectId,\n network,\n metadata,\n };\n\n // Only check for active sessions in SDK-managed mode where we have config\n const activeSessionData = await checkForActiveSession();\n\n if (activeSessionData) {\n // // Extract session details\n // const { topic, namespaces } = activeSessionData;\n // const accounts = namespaces?.ccd?.accounts || [];\n\n // // Emit active_session event to merchant with session data\n // window.dispatchEvent(\n // new CustomEvent('verification-web-ui-event', {\n // detail: {\n // type: 'active_session',\n // data: {\n // message: 'Active WalletConnect session detected',\n // timestamp: Date.now(),\n // topic,\n // accounts,\n // namespaces,\n // session: activeSessionData,\n // },\n // },\n // bubbles: true,\n // composed: true,\n // })\n // );\n\n // Close all existing modals (scan, landing, or any other modal)\n const allModals = document.querySelectorAll('.desktop--modal-overlay, .mobile--modal-overlay');\n allModals.forEach((modal) => {\n if (modal.parentNode) {\n modal.parentNode.removeChild(modal);\n }\n });\n\n // Reset scan modal reference\n scanModalElement = null;\n\n // Wait a moment to ensure DOM is cleaned\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n // Show returning user modal\n const { showReturningUserModal } = await import('./returning-user');\n await showReturningUserModal();\n return;\n }\n }\n }\n\n // No active session, proceed with QR code display\n\n if (connectionMode === 'sdk-managed') {\n // SDK manages WalletConnect - initialize and generate QR code\n await initializeSDKManagedConnection();\n } else {\n // Merchant provides the URI - use stored URI\n await initializeMerchantProvidedConnection();\n }\n } catch (error) {\n console.error('Wallet connection failed:', error);\n showQRError('Failed to generate QR code. Please try again.');\n }\n}\n\n/**\n * Initialize SDK-managed WalletConnect connection\n * SDK generates the QR code using project ID and network from localStorage\n */\nasync function initializeSDKManagedConnection(): Promise<void> {\n const projectId = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_PROJECT_ID);\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK) as 'mainnet' | 'testnet';\n\n if (!projectId || !network) {\n throw new Error('SDK project ID or network not found. Please call initWalletConnect() first.');\n }\n\n // Get WalletConnect service and generate URI\n const wcService = ServiceFactory.createWalletConnectService();\n await wcService.initialize();\n\n // Import WalletConnect constants for namespace configuration\n const { WalletConnectConstants } = await import('@/constants/walletconnect.constants');\n\n // Get the chain ID for the network\n const chainIds = WalletConnectConstants.CHAIN_IDS[network];\n\n // Generate WalletConnect URI by calling connect()\n const { uri, approval } = await wcService.connect({\n ccd: {\n methods: [WalletConnectConstants.METHODS.REQUEST_VERIFIABLE_PRESENTATION_V1],\n chains: chainIds,\n events: [...WalletConnectConstants.EVENTS],\n },\n });\n\n if (!uri) {\n throw new Error('Failed to generate WalletConnect URI from SDK');\n }\n\n // Store URI for mobile deep linking\n currentQRCodeUri = uri;\n\n // Handle session approval in the background\n approval()\n .then(async (session) => {\n await handleSessionApproval(session);\n })\n .catch((error) => {\n console.error('Session approval failed:', error);\n });\n\n // Check if mobile screen\n if (isMobileScreen()) {\n // For mobile, reveal the content (buttons, dropdown, steps)\n const mobileLoading = document.querySelector('#mobile-loading');\n const mobileContent = document.querySelector('#mobile-content');\n\n if (mobileLoading && mobileContent) {\n mobileLoading.classList.add(CSS_CLASSES.HIDDEN);\n mobileContent.classList.remove(CSS_CLASSES.HIDDEN);\n }\n } else {\n // For desktop, display QR code (which will also reveal elements)\n await displayQRCode(uri);\n }\n}\n\n/**\n * Initialize merchant-provided WalletConnect connection\n * Uses the URI provided by merchant via showWalletConnectPopup()\n */\nasync function initializeMerchantProvidedConnection(): Promise<void> {\n const storedUri = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.WALLET_CONNECT_URI);\n\n if (!storedUri) {\n showQRError(\n 'WalletConnect not configured. Please set up WalletConnect first by calling setWalletConnectUri() or initWalletConnect().'\n );\n return;\n }\n\n // Store URI for mobile deep linking\n currentQRCodeUri = storedUri;\n\n // Check if mobile screen\n if (isMobileScreen()) {\n // For mobile, reveal the content (buttons, dropdown, steps)\n const mobileLoading = document.querySelector('#mobile-loading');\n const mobileContent = document.querySelector('#mobile-content');\n\n if (mobileLoading && mobileContent) {\n mobileLoading.classList.add(CSS_CLASSES.HIDDEN);\n mobileContent.classList.remove(CSS_CLASSES.HIDDEN);\n }\n } else {\n // For desktop, display QR code (which will also reveal elements)\n await displayQRCode(storedUri);\n }\n}\n\n/**\n * Handles session approval and transitions to processing modal\n * Called when QR code is scanned and wallet approves the connection\n * @param sessionData - The session data from WalletConnect approval\n */\n/**\n * Handle WalletConnect session approval\n * Emits session_approved event to merchant and transitions to processing modal\n */\nexport async function handleSessionApproval(sessionData: any): Promise<void> {\n try {\n // Extract session details\n const { topic, namespaces } = sessionData;\n const accounts = namespaces?.ccd?.accounts || [];\n\n // Emit session approved event to merchant\n const sessionEvent = {\n topic,\n accounts,\n namespaces,\n };\n\n window.dispatchEvent(\n new CustomEvent('verification-web-ui-event', {\n detail: {\n type: 'session_approved',\n data: sessionEvent,\n },\n bubbles: true,\n composed: true,\n })\n );\n\n // Show the processing modal (it will handle crossfade with scan modal)\n const { showProcessingModal } = await import('./processing');\n await showProcessingModal();\n } catch (error) {\n console.error('Error handling session approval:', error);\n\n // Emit error event\n window.dispatchEvent(\n new CustomEvent('verification-web-ui-event', {\n detail: {\n type: 'error',\n data: {\n message: 'Failed to handle session approval',\n error,\n },\n },\n bubbles: true,\n composed: true,\n })\n );\n\n showQRError('Failed to process wallet connection. Please try again.');\n }\n}\n\nasync function displayQRCode(uri: string): Promise<void> {\n try {\n // Dynamic import following your coding instructions pattern\n const { default: QRCode } = await import('qrcode');\n const { getConfig } = await import('@/config.state');\n const config = getConfig();\n\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n\n if (qrContainer) {\n const qrCodeDataURL = await QRCode.toDataURL(uri, {\n width: 200,\n margin: 2,\n color: { dark: '#000000', light: '#ffffff' },\n });\n\n const showCountdown = config.qrCode?.showCountdown !== false;\n const countdownHTML = showCountdown\n ? '<p id=\"qr-countdown\" class=\"text-sm text-inverse-tertiary mt-2\">Expires in: <span class=\"font-semibold\">5:00</span></p>'\n : '';\n\n qrContainer.innerHTML = `\n <div class=\"text-center\">\n <img src=\"${qrCodeDataURL}\" alt=\"QR Code for wallet connection\" class=\"w-48 h-48 mx-auto mb-2\" style=\"border-radius: 12.414px; border: 1px solid rgba(0, 0, 0, 0.10); background: #FFF;\" />\n <p class=\"desktop--scan-text mt-2\">Scan the QR code with your<br>Concordium ID compatible device</p>\n ${countdownHTML}\n <img src=\"${sectionSeparator}\" alt=\"\" class=\"mx-auto mt-4\" />\n <div class=\"flex items-center justify-center mt-4\">\n <p class=\"desktop--download-text\">Download & Install the <a href=\"#\">Concordium ID App</a> and come back here to verify.</p>\n </div>\n </div>\n `;\n\n // Set up QR code expiry\n setupQRCodeExpiry();\n }\n } catch (error) {\n console.error('Failed to generate QR code:', error);\n showQRError('Failed to generate QR code. Please try again.');\n }\n}\n\n/**\n * Sets up QR code expiry timer and countdown\n */\nasync function setupQRCodeExpiry(): Promise<void> {\n // Clear any existing timers\n if (qrExpiryTimer) {\n clearTimeout(qrExpiryTimer);\n qrExpiryTimer = null;\n }\n if (qrCountdownInterval) {\n clearInterval(qrCountdownInterval);\n qrCountdownInterval = null;\n }\n\n const { getConfig } = await import('@/config.state');\n const config = getConfig();\n\n const expiryDuration = config.qrCode?.expiryDuration || 5 * 60 * 1000; // Default 5 minutes\n const showCountdown = config.qrCode?.showCountdown !== false;\n const autoRefresh = config.qrCode?.autoRefresh !== false;\n\n const expiryTime = Date.now() + expiryDuration;\n\n // Set up countdown display\n if (showCountdown) {\n const countdownElement = document.querySelector('#qr-countdown span');\n if (countdownElement) {\n qrCountdownInterval = setInterval(() => {\n const remaining = Math.max(0, expiryTime - Date.now());\n const minutes = Math.floor(remaining / 60000);\n const seconds = Math.floor((remaining % 60000) / 1000);\n countdownElement.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;\n\n if (remaining <= 0) {\n if (qrCountdownInterval) {\n clearInterval(qrCountdownInterval);\n qrCountdownInterval = null;\n }\n }\n }, 1000);\n }\n }\n\n // Set up expiry timer\n qrExpiryTimer = setTimeout(async () => {\n await handleQRCodeExpiry(autoRefresh);\n }, expiryDuration);\n}\n\n/**\n * Handles QR code expiry event\n * @param autoRefresh - Whether to automatically refresh the QR code\n */\nasync function handleQRCodeExpiry(autoRefresh: boolean): Promise<void> {\n const connectionMode = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.CONNECTION_MODE);\n const isMerchantProvided = connectionMode !== 'sdk-managed';\n\n // Dispatch expiry event\n dispatchConcordiumEvent({\n type: 'qr-code-expired',\n source: 'desktop',\n modalType: 'scan',\n data: {\n connectionMode,\n isMerchantProvided,\n autoRefresh: isMerchantProvided ? false : autoRefresh,\n },\n });\n\n if (isMerchantProvided) {\n // Merchant-provided QR code expired - notify merchant, don't auto-refresh\n showQRExpiredMessage(false);\n } else if (autoRefresh) {\n // SDK-managed QR code with auto-refresh enabled\n showQRRefreshing();\n await refreshQRCode();\n } else {\n // SDK-managed but auto-refresh disabled\n showQRExpiredMessage(true);\n }\n}\n\n/**\n * Refreshes the QR code (SDK-managed only)\n */\nasync function refreshQRCode(): Promise<void> {\n try {\n // Re-initialize SDK-managed connection to get new URI\n await initializeSDKManagedConnection();\n\n // Dispatch refresh event\n dispatchConcordiumEvent({\n type: 'qr-code-refreshed',\n source: 'desktop',\n modalType: 'scan',\n data: {\n timestamp: Date.now(),\n },\n });\n } catch (error) {\n console.error('Failed to refresh QR code:', error);\n showQRError('Failed to refresh QR code. Please try again.');\n }\n}\n\n/**\n * Shows QR expired message with optional manual refresh button\n */\nfunction showQRExpiredMessage(canRefresh: boolean): void {\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n if (qrContainer) {\n const refreshButtonHTML = canRefresh\n ? `<button id=\"refresh-qr\" class=\"mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm\">\n Refresh QR Code\n </button>`\n : `<p class=\"text-sm text-inverse-tertiary mt-2\">Waiting for new QR code from merchant...</p>`;\n\n qrContainer.innerHTML = `\n <div class=\"text-center\">\n <div class=\"w-48 h-48 bg-yellow-50 border-2 border-yellow-200 rounded flex items-center justify-center mx-auto mb-2\">\n <svg class=\"w-16 h-16 text-yellow-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n </div>\n <p class=\"text-sm text-yellow-600 font-semibold\">QR Code Expired</p>\n ${refreshButtonHTML}\n </div>\n `;\n\n // Add manual refresh functionality\n if (canRefresh) {\n const refreshBtn = qrContainer.querySelector('#refresh-qr');\n if (refreshBtn) {\n refreshBtn.addEventListener('click', async () => {\n showQRRefreshing();\n await refreshQRCode();\n });\n }\n }\n }\n}\n\n/**\n * Shows QR refreshing loading state\n */\nfunction showQRRefreshing(): void {\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n if (qrContainer) {\n qrContainer.innerHTML = `\n <div class=\"animate-pulse text-center\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2 mx-auto\"></div>\n <p class=\"text-sm text-inverse-tertiary\">Refreshing QR code...</p>\n </div>\n `;\n }\n}\n\n/**\n * Updates QR code from merchant-provided URI\n * Called when merchant provides a new URI after expiry\n * @param newUri - The new WalletConnect URI from merchant\n */\nexport async function updateQRCodeFromMerchant(newUri: string): Promise<void> {\n // Display the new QR code\n await displayQRCode(newUri);\n\n // Dispatch refresh event\n dispatchConcordiumEvent({\n type: 'qr-code-refreshed',\n source: 'desktop',\n modalType: 'scan',\n data: {\n timestamp: Date.now(),\n source: 'merchant',\n },\n });\n}\n\nfunction showQRError(message: string): void {\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n if (qrContainer) {\n qrContainer.innerHTML = `\n <div class=\"text-center\">\n <div class=\"w-48 h-48 bg-red-50 border-2 border-red-200 rounded flex items-center justify-center mx-auto mb-2\">\n <svg class=\"w-16 h-16 text-red-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\"></path>\n </svg>\n </div>\n <p class=\"text-sm text-red-600\">${message}</p>\n <button id=\"retry-qr\" class=\"mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm\">\n Retry\n </button>\n </div>\n `;\n\n // Add retry functionality\n const retryBtn = qrContainer.querySelector('#retry-qr');\n if (retryBtn) {\n retryBtn.addEventListener('click', async () => {\n // Reset to loading state\n qrContainer.innerHTML = `\n <div class=\"animate-pulse text-center\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2 mx-auto\"></div>\n <p class=\"text-sm text-inverse-tertiary\">Generating QR code...</p>\n </div>\n `;\n\n // Retry connection\n await initializeWalletConnection();\n });\n }\n }\n}\n\n/**\n * Sets up event listeners for session approval and verification\n */\nfunction setupEventListeners(): void {\n const listeners: Array<() => void> = [];\n\n // Listen for session-approved event to transition to processing modal\n const handleSessionApproved = async (_event: Event) => {\n // Hide scan modal first and wait for it to be removed\n hideScanModal();\n\n // Wait for scan modal to be fully removed from DOM\n await new Promise((resolve) => setTimeout(resolve, 350));\n\n // Transition to processing modal\n const { showProcessingModal } = await import('./processing');\n await showProcessingModal();\n };\n\n // Add event listeners\n window.addEventListener('concordium-event', (event) => {\n const customEvent = event as CustomEvent;\n if (customEvent.detail?.type === 'session-approved') {\n handleSessionApproved(event);\n }\n });\n\n // Store cleanup function\n const cleanup = () => {\n window.removeEventListener('concordium-event', handleSessionApproved);\n };\n\n listeners.push(cleanup);\n (window as any).scanEventListeners = listeners;\n}\n\n/**\n * Checks for active WalletConnect sessions\n * @returns Session data if there are active sessions, null otherwise\n */\nasync function checkForActiveSession(): Promise<any | null> {\n try {\n const { ServiceFactory } = await import('@/services');\n const walletConnectService = ServiceFactory.createWalletConnectService();\n\n await walletConnectService.initialize();\n const activeSessions = walletConnectService.getActiveSessions();\n\n if (activeSessions.length > 0) {\n // Return the first active session data\n return activeSessions[0];\n }\n\n return null;\n } catch (error) {\n console.error('Failed to check for active sessions:', error);\n return null;\n }\n}\n\n/**\n * Generates deep link for mobile wallets\n * @param walletType - The wallet type (concordium-wallet or concordium-id)\n * @param uri - The WalletConnect URI\n * @returns The deep link URL\n */\nfunction generateDeepLink(walletType: WalletTypeValues, uri: string): string | null {\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK) || 'testnet';\n const ua = navigator.userAgent;\n let deepLink: string | null = null;\n\n if (walletType === WALLET_TYPES.CONCORDIUM_WALLET) {\n // Check device type for Concordium Wallet\n if (/iPad|iPhone|iPod/.test(ua) && !(window as any).MSStream) {\n // iOS\n deepLink = `cryptox${network}://wc?uri=${encodeURIComponent(uri)}&redirect=googlechrome://`;\n } else if (/android/i.test(ua)) {\n // Android\n deepLink = `cryptox-wc-${network}://wc?uri=${encodeURIComponent(uri)}&go_back=true`;\n }\n } else if (walletType === WALLET_TYPES.CONCORDIUM_ID) {\n // Concordium ID - same for all devices, with redirect to origin\n const redirectUrl = encodeURIComponent(window.location.href);\n deepLink = `concordiumidapp://wc?uri=${encodeURIComponent(uri)}&redirect=${redirectUrl}`;\n }\n\n return deepLink;\n}\n\n/**\n * Displays QR code on mobile (when user chooses to verify on another device)\n * @param uri - The WalletConnect URI\n * @param container - The container element to display QR code in\n */\nasync function displayQRCodeMobile(uri: string, container: HTMLElement): Promise<void> {\n try {\n const { default: QRCode } = await import('qrcode');\n\n const qrCodeDataURL = await QRCode.toDataURL(uri, {\n width: 200,\n margin: 2,\n color: { dark: '#000000', light: '#ffffff' },\n });\n\n container.innerHTML = `\n <div class=\"text-center py-4\">\n <img src=\"${qrCodeDataURL}\" alt=\"QR Code for wallet connection\" class=\"w-48 h-48 mx-auto mb-2\" style=\"border-radius: 12.414px; border: 1px solid rgba(0, 0, 0, 0.10); background: #FFF;\" />\n <p class=\"desktop--scan-text\">Scan the QR code with your<br>Concordium ID compatible device</p>\n <img src=\"${sectionSeparator}\" alt=\"\" class=\"mx-auto mt-4\" />\n <div class=\"flex items-center justify-center mt-4\">\n <p class=\"desktop--download-text\">Download & Install the <a href=\"#\">Concordium ID App</a> and come back here to verify.</p>\n </div>\n </div>\n `;\n\n // Show the container\n container.classList.remove(CSS_CLASSES.HIDDEN);\n container.style.display = 'flex';\n } catch (error) {\n console.error('[Mobile] Failed to generate QR code:', error);\n }\n}\n"],"names":["ServiceFactory"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scan.js","sources":["../../../src/components/desktop/scan.ts"],"sourcesContent":["// scan.ts - Scan Modal Implementation\nimport arrowLeft from '@/assets/arrow-left.svg';\nimport arrowRight from '@/assets/arrow-right.svg';\nimport concordiumModalLogo from '@/assets/concordium-modal-logo.svg';\nimport sectionSeparator from '@/assets/section-separator.svg';\nimport { isMobileScreen } from '@/config.state';\nimport { ModalConstants } from '@/constants/modal.constants';\nimport { dispatchConcordiumEvent } from '@/index';\nimport { ServiceFactory } from '@/services';\nimport type { HideModalFunction, ModalFunction, ShowModalFunction } from '@/types';\n\n// Global variables for modal state management\nlet scanModalElement: HTMLElement | null = null;\nlet processingTimeout: ReturnType<typeof setTimeout> | null = null;\nlet qrExpiryTimer: ReturnType<typeof setTimeout> | null = null;\nlet qrCountdownInterval: ReturnType<typeof setInterval> | null = null;\nlet currentQRCodeUri: string | null = null;\nlet currentSelectedWallet: WalletTypeValues;\n\n// Constants\nconst WALLET_TYPES = {\n CONCORDIUM_WALLET: 'concordium-wallet',\n BROWSER_WALLET: 'browser-wallet',\n CONCORDIUM_ID: 'concordium-id',\n} as const;\n\n// Initialize after WALLET_TYPES is defined\ncurrentSelectedWallet = WALLET_TYPES.CONCORDIUM_ID;\n\ntype WalletTypeKeys = keyof typeof WALLET_TYPES;\ntype WalletTypeValues = (typeof WALLET_TYPES)[WalletTypeKeys];\n\nconst CSS_CLASSES = {\n HIDDEN: 'hidden',\n FLEX: 'flex',\n FLEX_COL: 'flex-col',\n} as const;\n\nconst SELECTORS = {\n APP: '#app',\n SCAN_MODAL: '#scan-modal',\n BACK_BTN: '#back-btn',\n QR_CONTAINER: '#qr-container',\n BROWSER_BTN: '#browser-btn',\n BROWSER_WALLET_BTN: '#browser-wallet-btn',\n} as const;\n\n// Helper function to create desktop HTML\nfunction createDesktopScanHTML(): string {\n return `\n <div class=\"desktop--modal-overlay\">\n <div class=\"desktop--modal-container\">\n <div class=\"desktop--modal-body\">\n <div class=\"flex items-center justify-between p-2\">\n <button class=\"desktop--navigation-button\" id=\"back-btn\">\n <img src=\"${arrowLeft}\" alt=\"arrow-left-icon\" />\n <span>Back</span>\n </button>\n <div>\n <img src=\"${concordiumModalLogo}\" alt=\"concordium-modal-logo\" />\n </div>\n </div>\n\n <div id=\"qr-container\" class=\"${CSS_CLASSES.FLEX} items-center justify-center\" style=\"min-height: 380px;\">\n <div class=\"animate-pulse text-center\" style=\"display: flex; flex-direction: column; justify-content: center; align-items: center;\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2\"></div>\n <p class=\"text-sm\" style=\"color: #0D0F11;\">Generating QR code...</p>\n </div>\n </div>\n\n <div id=\"browser-btn\" class=\"${CSS_CLASSES.HIDDEN} ${CSS_CLASSES.FLEX_COL} items-center gap-4\">\n <button class=\"desktop--primary-button\" id=\"browser-wallet-btn\">\n <span>Verify with Browser Wallet</span>\n <img src=\"${arrowRight}\" alt=\"arrow-right-icon\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n `;\n}\n\n// Helper function to create mobile HTML\nfunction createMobileScanHTML(): string {\n return `\n <div class=\"mobile--modal-overlay position-relative\">\n <div class=\"mobile--modal-container\">\n <div class=\"mobile--modal-body\">\n <div class=\"flex items-center justify-between p-2\">\n <button class=\"mobile--navigation-button\" id=\"back-btn\">\n <img src=\"${arrowLeft}\" alt=\"arrow-left-icon\" />\n <span>Back</span>\n </button>\n <div>\n <img src=\"${concordiumModalLogo}\" alt=\"concordium-modal-logo\" />\n </div>\n </div>\n\n <div id=\"mobile-loading\" class=\"${CSS_CLASSES.FLEX} items-center justify-center min-h-[300px]\">\n <div class=\"animate-pulse text-center\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2 mx-auto\"></div>\n <p class=\"text-sm\" style=\"color: #0D0F11;\">Preparing wallet connection...</p>\n </div>\n </div>\n\n <div id=\"mobile-content\" class=\"${CSS_CLASSES.HIDDEN}\">\n <div id=\"btn-wrapper\" class=\"flex flex-col w-full items-center gap-2 mt-4\">\n <button class=\"mobile--primary-button w-full\" id=\"open-in-wallet-btn\">\n <span id=\"wallet-btn-text\">Verify with ConcordiumID</span>\n <img src=\"${arrowRight}\" alt=\"arrow-right-icon\" />\n </button>\n <button class=\"mobile--primary-outline-button w-full\" id=\"open-other-device-btn\">\n <span>Verify on Another Device</span>\n </button>\n </div>\n\n <div id=\"qr-container\" class=\"${CSS_CLASSES.HIDDEN}\" style=\"display: none;\">\n <!-- QR code will be generated here when user clicks \"Verify on Another Device\" -->\n </div>\n </div>\n </div>\n </div>\n </div>\n `;\n}\n\nexport const createScanModal: ModalFunction = () => {\n // Detect if mobile screen\n const isMobile = isMobileScreen();\n\n const scanHTML = isMobile ? createMobileScanHTML() : createDesktopScanHTML();\n\n const scanContainer = document.createElement('div');\n scanContainer.innerHTML = scanHTML;\n scanContainer.id = 'scan-modal';\n\n // Cache DOM elements for better performance\n const elements = {\n backBtn: scanContainer.querySelector(SELECTORS.BACK_BTN) as HTMLButtonElement | null,\n browserWalletBtn: scanContainer.querySelector(SELECTORS.BROWSER_WALLET_BTN) as HTMLButtonElement | null,\n openInWalletBtn: scanContainer.querySelector('#open-in-wallet-btn') as HTMLButtonElement | null,\n openOtherDeviceBtn: scanContainer.querySelector('#open-other-device-btn') as HTMLButtonElement | null,\n qrContainer: scanContainer.querySelector(SELECTORS.QR_CONTAINER) as HTMLElement | null,\n };\n\n // Event handlers following your modal navigation pattern\n const handleBack = async (): Promise<void> => {\n const { showLandingModal } = await import('./landing');\n hideScanModal();\n await showLandingModal();\n };\n\n const handleBrowserWallet = async (): Promise<void> => {\n // Processing modal will be shown automatically after session approval\n // Don't hide scan modal - keep it visible until session is established\n };\n\n // Mobile-specific handlers\n const handleOpenInWallet = async (): Promise<void> => {\n try {\n // Check if URI is available\n if (!currentQRCodeUri) {\n const storedUri = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.WALLET_CONNECT_URI);\n if (storedUri) {\n currentQRCodeUri = storedUri;\n } else {\n await initializeWalletConnection();\n if (!currentQRCodeUri) {\n alert('Connection URI not available. Please refresh and try again.');\n return;\n }\n }\n }\n\n // Determine app type based on selection\n const appType =\n currentSelectedWallet === WALLET_TYPES.CONCORDIUM_ID ? 'concordium-id' : 'concordium-wallet';\n\n // Generate and open deep link directly (simpler approach)\n const deepLink = generateDeepLink(currentSelectedWallet, currentQRCodeUri!);\n\n if (deepLink) {\n window.location.href = deepLink;\n } else {\n // Fallback: try to open app store\n const { openAppStore } = await import('@/utils/mobileAppDetection');\n openAppStore(appType);\n }\n } catch (error) {\n console.error('[Mobile] handleOpenInWallet failed:', error);\n alert('Failed to open wallet app. Please try again.');\n }\n };\n\n const handleOpenOtherDevice = async (): Promise<void> => {\n const btnWrapper = scanContainer.querySelector('#btn-wrapper');\n if (btnWrapper) {\n btnWrapper.classList.add(CSS_CLASSES.HIDDEN);\n }\n\n if (currentQRCodeUri && elements.qrContainer) {\n await displayQRCodeMobile(currentQRCodeUri, elements.qrContainer);\n }\n };\n\n // Attach event listeners with null safety\n elements.backBtn?.addEventListener('click', handleBack);\n elements.browserWalletBtn?.addEventListener('click', handleBrowserWallet);\n\n // Mobile-specific event listeners\n if (isMobile) {\n elements.openInWalletBtn?.addEventListener('click', handleOpenInWallet);\n elements.openOtherDeviceBtn?.addEventListener('click', handleOpenOtherDevice);\n }\n\n return scanContainer;\n};\n\nexport const showScanModal: ShowModalFunction = async () => {\n const { getGlobalContainer } = await import('../../index');\n const targetContainer = getGlobalContainer();\n\n if (!targetContainer) {\n console.error('Container not found for modal');\n return;\n }\n\n // Detect mobile/desktop mode\n const isMobile = isMobileScreen();\n const containerClass = isMobile ? '.mobile--modal-container' : '.desktop--modal-container';\n\n // Create and store modal element reference\n scanModalElement = createScanModal();\n scanModalElement.id = 'scan-modal';\n\n // Get the modal container for transforms\n const modalContainer = scanModalElement.querySelector(containerClass) as HTMLElement | null;\n\n // For smooth transitions, prepare new modal completely before showing\n scanModalElement.style.opacity = '0';\n if (modalContainer) {\n modalContainer.style.transform = 'translateY(-20px) scale(0.95)';\n modalContainer.style.transition = 'transform 0.3s ease-out';\n }\n targetContainer.appendChild(scanModalElement);\n\n // Force a reflow to ensure the styles are applied\n scanModalElement.offsetHeight;\n\n // Now start the transition\n scanModalElement.style.transition = 'opacity 0.3s ease-out';\n\n // Use a small delay to ensure DOM is fully ready\n setTimeout(() => {\n // Check if modal still exists (may have been removed by active session detection)\n if (!scanModalElement) {\n return;\n }\n\n // Show new modal\n scanModalElement.style.opacity = '1';\n if (modalContainer) {\n modalContainer.style.transform = 'translateY(0) scale(1)';\n }\n }, 10);\n\n // Set up event listeners for session approval and verification completion\n setupEventListeners();\n\n // Initialize WalletConnect after modal is mounted\n await initializeWalletConnection();\n};\n\nexport const hideScanModal: HideModalFunction = () => {\n if (scanModalElement) {\n // Clean up dropdown instance following your cleanup pattern\n if ((scanModalElement as any).dropdownInstance?.destroy) {\n (scanModalElement as any).dropdownInstance.destroy();\n }\n\n // Add fade-out animation\n scanModalElement.classList.add('modal-exiting');\n\n // Remove from DOM after animation completes\n setTimeout(() => {\n const container = scanModalElement?.parentNode;\n if (container && scanModalElement) {\n container.removeChild(scanModalElement);\n }\n scanModalElement = null;\n // Restore body overflow if no other modals are present\n if (\n !document.querySelector('.desktop--modal-overlay') &&\n !document.querySelector('.mobile--modal-overlay')\n ) {\n document.body.style.overflowX = '';\n }\n }, 300);\n }\n\n // Clear any active timers\n if (processingTimeout) {\n clearTimeout(processingTimeout);\n processingTimeout = null;\n }\n\n // Clear QR code expiry timers\n if (qrExpiryTimer) {\n clearTimeout(qrExpiryTimer);\n qrExpiryTimer = null;\n }\n\n if (qrCountdownInterval) {\n clearInterval(qrCountdownInterval);\n qrCountdownInterval = null;\n }\n\n // Clean up event listeners following your cleanup pattern\n if ((window as any).scanEventCleanup) {\n (window as any).scanEventCleanup();\n (window as any).scanEventCleanup = null;\n }\n\n // Clean up custom event listeners\n if ((window as any).scanEventListeners) {\n (window as any).scanEventListeners.forEach((cleanup: () => void) => cleanup());\n (window as any).scanEventListeners = null;\n }\n};\n\n// WalletConnect initialization function\nasync function initializeWalletConnection(): Promise<void> {\n try {\n // Check connection mode to determine how to handle WalletConnect\n const connectionMode = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.CONNECTION_MODE);\n\n // Set up WalletConnect config early if in SDK-managed mode\n if (connectionMode === 'sdk-managed') {\n const projectId = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_PROJECT_ID);\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK);\n const metadataStr = localStorage.getItem('sdkWalletConnectMetadata');\n const metadata = metadataStr ? JSON.parse(metadataStr) : null;\n\n if (projectId && network) {\n // Store the config globally so ServiceFactory can use it\n (window as any).__CONCORDIUM_WC_CONFIG__ = {\n projectId,\n network,\n metadata,\n };\n\n // Only check for active sessions in SDK-managed mode where we have config\n const activeSessionData = await checkForActiveSession();\n\n if (activeSessionData) {\n // // Extract session details\n // const { topic, namespaces } = activeSessionData;\n // const accounts = namespaces?.ccd?.accounts || [];\n\n // // Emit active_session event to merchant with session data\n // window.dispatchEvent(\n // new CustomEvent('verification-web-ui-event', {\n // detail: {\n // type: 'active_session',\n // data: {\n // message: 'Active WalletConnect session detected',\n // timestamp: Date.now(),\n // topic,\n // accounts,\n // namespaces,\n // session: activeSessionData,\n // },\n // },\n // bubbles: true,\n // composed: true,\n // })\n // );\n\n // Close all existing modals (scan, landing, or any other modal)\n const allModals = document.querySelectorAll('.desktop--modal-overlay, .mobile--modal-overlay');\n allModals.forEach((modal) => {\n if (modal.parentNode) {\n modal.parentNode.removeChild(modal);\n }\n });\n\n // Reset scan modal reference\n scanModalElement = null;\n\n // Wait a moment to ensure DOM is cleaned\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n // Show returning user modal\n const { showReturningUserModal } = await import('./returning-user');\n await showReturningUserModal();\n return;\n }\n }\n }\n\n // No active session, proceed with QR code display\n\n if (connectionMode === 'sdk-managed') {\n // SDK manages WalletConnect - initialize and generate QR code\n await initializeSDKManagedConnection();\n } else {\n // Merchant provides the URI - use stored URI\n await initializeMerchantProvidedConnection();\n }\n } catch (error) {\n console.error('Wallet connection failed:', error);\n showQRError('Failed to generate QR code. Please try again.');\n }\n}\n\n/**\n * Initialize SDK-managed WalletConnect connection\n * SDK generates the QR code using project ID and network from localStorage\n */\nasync function initializeSDKManagedConnection(): Promise<void> {\n const projectId = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_PROJECT_ID);\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK) as 'mainnet' | 'testnet';\n\n if (!projectId || !network) {\n throw new Error('SDK project ID or network not found. Please call initWalletConnect() first.');\n }\n\n // Get WalletConnect service and generate URI\n const wcService = ServiceFactory.createWalletConnectService();\n await wcService.initialize();\n\n // Clear all existing sessions before creating new pairing\n // This prevents conflicts when user tries different wallets\n await wcService.clearAllSessionsForNewPairing();\n\n // Import WalletConnect constants for namespace configuration\n const { WalletConnectConstants } = await import('@/constants/walletconnect.constants');\n\n // Get the chain ID for the network\n const chainIds = WalletConnectConstants.CHAIN_IDS[network];\n\n // Generate WalletConnect URI by calling connect()\n const { uri, approval } = await wcService.connect({\n ccd: {\n // Request all methods for broad wallet compatibility\n // This allows both ID App (v1) and Concordium Wallet (v0) to connect\n methods: [...WalletConnectConstants.ALL_METHODS],\n chains: chainIds,\n events: [...WalletConnectConstants.EVENTS],\n },\n });\n\n if (!uri) {\n throw new Error('Failed to generate WalletConnect URI from SDK');\n }\n\n // Store URI for mobile deep linking\n currentQRCodeUri = uri;\n\n // Handle session approval in the background\n approval()\n .then(async (session) => {\n await handleSessionApproval(session);\n })\n .catch((error) => {\n console.error('Session approval failed:', error);\n });\n\n // Check if mobile screen\n if (isMobileScreen()) {\n // For mobile, reveal the content (buttons, dropdown, steps)\n const mobileLoading = document.querySelector('#mobile-loading');\n const mobileContent = document.querySelector('#mobile-content');\n\n if (mobileLoading && mobileContent) {\n mobileLoading.classList.add(CSS_CLASSES.HIDDEN);\n mobileContent.classList.remove(CSS_CLASSES.HIDDEN);\n }\n } else {\n // For desktop, display QR code (which will also reveal elements)\n await displayQRCode(uri);\n }\n}\n\n/**\n * Initialize merchant-provided WalletConnect connection\n * Uses the URI provided by merchant via showWalletConnectPopup()\n */\nasync function initializeMerchantProvidedConnection(): Promise<void> {\n const storedUri = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.WALLET_CONNECT_URI);\n\n if (!storedUri) {\n showQRError(\n 'WalletConnect not configured. Please set up WalletConnect first by calling setWalletConnectUri() or initWalletConnect().'\n );\n return;\n }\n\n // Store URI for mobile deep linking\n currentQRCodeUri = storedUri;\n\n // Check if mobile screen\n if (isMobileScreen()) {\n // For mobile, reveal the content (buttons, dropdown, steps)\n const mobileLoading = document.querySelector('#mobile-loading');\n const mobileContent = document.querySelector('#mobile-content');\n\n if (mobileLoading && mobileContent) {\n mobileLoading.classList.add(CSS_CLASSES.HIDDEN);\n mobileContent.classList.remove(CSS_CLASSES.HIDDEN);\n }\n } else {\n // For desktop, display QR code (which will also reveal elements)\n await displayQRCode(storedUri);\n }\n}\n\n/**\n * Auto-send the presentation request if one is configured in localStorage.\n * This is called after session approval to automatically trigger verification.\n * Tries v1 method first (ID App), then falls back to v0 (Concordium Wallet).\n * @param topic - The session topic to use for the request\n */\nexport async function autoSendPresentationRequestIfConfigured(topic: string): Promise<void> {\n try {\n const presentationRequestStr = localStorage.getItem(\n ModalConstants.LOCAL_STORAGE_FLAGS.SDK_PRESENTATION_REQUEST\n );\n if (!presentationRequestStr) {\n console.log('No presentation request configured, waiting for merchant to send request');\n return;\n }\n\n const presentationRequest = JSON.parse(presentationRequestStr);\n console.log('Auto-sending presentation request:', presentationRequest);\n\n // Get the WalletConnect service\n const wcService = ServiceFactory.getWalletConnectService();\n if (!wcService) {\n console.error('WalletConnect service not available for auto-send');\n return;\n }\n\n // Get network configuration\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK) as 'mainnet' | 'testnet';\n const chainId =\n network === 'mainnet' ? import.meta.env.VITE_CHAIN_ID_MAINNET : import.meta.env.VITE_CHAIN_ID_TESTNET;\n\n // Get metadata from localStorage\n const metadataStr = localStorage.getItem('sdkWalletConnectMetadata');\n const storedMetadata = metadataStr ? JSON.parse(metadataStr) : {};\n\n const metadata = {\n description: storedMetadata?.description || 'Requesting verification',\n appName: storedMetadata?.name || 'Concordium Verification WebUI',\n url: storedMetadata?.url || window.location.origin,\n icons: storedMetadata?.icons || [],\n };\n\n // Try v1 method first (ID App), then fallback to v0 (Concordium Wallet)\n let response: any;\n let methodUsed: string;\n\n try {\n // Try v1 first (Concordium ID App)\n console.log('Trying v1 method (request_verifiable_presentation_v1)...');\n response = await wcService.request({\n topic,\n chainId,\n request: {\n method: 'request_verifiable_presentation_v1',\n params: {\n ...presentationRequest,\n metadata,\n },\n },\n });\n methodUsed = 'v1';\n } catch (v1Error) {\n console.log('v1 method failed, trying v0 method...', v1Error);\n // Fallback to v0 (Concordium Wallet)\n response = await wcService.request({\n topic,\n chainId,\n request: {\n method: 'request_verifiable_presentation',\n params: {\n ...presentationRequest,\n metadata,\n },\n },\n });\n methodUsed = 'v0';\n }\n\n console.log(`Presentation response received (method ${methodUsed}):`, response);\n\n // Emit the response to merchant\n window.dispatchEvent(\n new CustomEvent('verification-web-ui-event', {\n detail: {\n type: 'presentation_received',\n data: response,\n },\n bubbles: true,\n composed: true,\n })\n );\n\n // Show success state\n const { showSuccessState } = await import('./processing');\n await showSuccessState();\n } catch (error) {\n console.error('Failed to auto-send presentation request:', error);\n\n // Emit error event\n window.dispatchEvent(\n new CustomEvent('verification-web-ui-event', {\n detail: {\n type: 'error',\n data: {\n message: 'Failed to send verification request',\n error,\n },\n },\n bubbles: true,\n composed: true,\n })\n );\n\n // Show error state\n const { showErrorState } = await import('./processing');\n await showErrorState();\n }\n}\n\n/**\n * Handle WalletConnect session approval\n * Emits session_approved event to merchant and transitions to processing modal\n * If a presentationRequest is configured, automatically sends the verification request\n */\nexport async function handleSessionApproval(sessionData: any): Promise<void> {\n try {\n // Extract session details\n const { topic, namespaces } = sessionData;\n const accounts = namespaces?.ccd?.accounts || [];\n\n // Extract and store connected wallet name from peer metadata\n const walletName = sessionData.peer?.metadata?.name || 'Wallet';\n localStorage.setItem(ModalConstants.LOCAL_STORAGE_FLAGS.CONNECTED_WALLET_NAME, walletName);\n\n // Emit session approved event to merchant\n const sessionEvent = {\n topic,\n accounts,\n namespaces,\n walletName,\n };\n\n window.dispatchEvent(\n new CustomEvent('verification-web-ui-event', {\n detail: {\n type: 'session_approved',\n data: sessionEvent,\n },\n bubbles: true,\n composed: true,\n })\n );\n\n // Show the processing modal (it will handle crossfade with scan modal)\n const { showProcessingModal } = await import('./processing');\n await showProcessingModal();\n\n // Check if there's a presentation request to auto-send\n await autoSendPresentationRequestIfConfigured(topic);\n } catch (error) {\n console.error('Error handling session approval:', error);\n\n // Emit error event\n window.dispatchEvent(\n new CustomEvent('verification-web-ui-event', {\n detail: {\n type: 'error',\n data: {\n message: 'Failed to handle session approval',\n error,\n },\n },\n bubbles: true,\n composed: true,\n })\n );\n\n showQRError('Failed to process wallet connection. Please try again.');\n }\n}\n\nasync function displayQRCode(uri: string): Promise<void> {\n try {\n // Dynamic import following your coding instructions pattern\n const { default: QRCode } = await import('qrcode');\n const { getConfig } = await import('@/config.state');\n const { getConcordiumIdDeepLink } = await import('@/constants/wallet.registry');\n const config = getConfig();\n\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n\n if (qrContainer) {\n // Use Concordium ID app deep link format: concordiumidapp://wc?uri=<encoded-wc-uri>\n // This allows ID app to scan and recognize its own deep link format\n const qrValue = getConcordiumIdDeepLink(uri);\n console.log('Generated QR code value:', qrValue);\n\n const qrCodeDataURL = await QRCode.toDataURL(qrValue, {\n width: 200,\n margin: 2,\n color: { dark: '#000000', light: '#ffffff' },\n });\n\n const showCountdown = config.qrCode?.showCountdown !== false;\n const countdownHTML = showCountdown\n ? '<p id=\"qr-countdown\" class=\"text-sm text-inverse-tertiary mt-2\">Expires in: <span class=\"font-semibold\">5:00</span></p>'\n : '';\n\n // Determine app store link based on user's device\n const { getIdAppStoreUrl } = await import('@/constants/wallet.registry');\n const appStoreUrl = getIdAppStoreUrl();\n\n qrContainer.innerHTML = `\n <div class=\"text-center\" style=\"min-height: 350px; display: flex; flex-direction: column; justify-content: center;\">\n <img src=\"${qrCodeDataURL}\" alt=\"QR Code for wallet connection\" class=\"w-48 h-48 mx-auto mb-2\" style=\"border-radius: 12.414px; border: 1px solid rgba(0, 0, 0, 0.10); background: #FFF;\" />\n <p class=\"desktop--scan-text mt-2\">Scan the QR code with your<br>Concordium ID compatible device</p>\n ${countdownHTML}\n <img src=\"${sectionSeparator}\" alt=\"\" class=\"mx-auto mt-4\" />\n <div class=\"flex items-center justify-center mt-4\">\n <p class=\"desktop--download-text\">Download & Install the <a href=\"${appStoreUrl}\" target=\"_blank\" rel=\"noopener noreferrer\">Concordium ID App</a> and come back here to verify.</p>\n </div>\n </div>\n `;\n\n // Set up QR code expiry\n setupQRCodeExpiry();\n }\n } catch (error) {\n console.error('Failed to generate QR code:', error);\n showQRError('Failed to generate QR code. Please try again.');\n }\n}\n\n/**\n * Sets up QR code expiry timer and countdown\n */\nasync function setupQRCodeExpiry(): Promise<void> {\n // Clear any existing timers\n if (qrExpiryTimer) {\n clearTimeout(qrExpiryTimer);\n qrExpiryTimer = null;\n }\n if (qrCountdownInterval) {\n clearInterval(qrCountdownInterval);\n qrCountdownInterval = null;\n }\n\n const { getConfig } = await import('@/config.state');\n const config = getConfig();\n\n const expiryDuration = config.qrCode?.expiryDuration || 5 * 60 * 1000; // Default 5 minutes\n const showCountdown = config.qrCode?.showCountdown !== false;\n const autoRefresh = config.qrCode?.autoRefresh !== false;\n\n const expiryTime = Date.now() + expiryDuration;\n\n // Set up countdown display\n if (showCountdown) {\n const countdownElement = document.querySelector('#qr-countdown span');\n if (countdownElement) {\n qrCountdownInterval = setInterval(() => {\n const remaining = Math.max(0, expiryTime - Date.now());\n const minutes = Math.floor(remaining / 60000);\n const seconds = Math.floor((remaining % 60000) / 1000);\n countdownElement.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;\n\n if (remaining <= 0) {\n if (qrCountdownInterval) {\n clearInterval(qrCountdownInterval);\n qrCountdownInterval = null;\n }\n }\n }, 1000);\n }\n }\n\n // Set up expiry timer\n qrExpiryTimer = setTimeout(async () => {\n await handleQRCodeExpiry(autoRefresh);\n }, expiryDuration);\n}\n\n/**\n * Handles QR code expiry event\n * @param autoRefresh - Whether to automatically refresh the QR code\n */\nasync function handleQRCodeExpiry(autoRefresh: boolean): Promise<void> {\n const connectionMode = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.CONNECTION_MODE);\n const isMerchantProvided = connectionMode !== 'sdk-managed';\n\n // Dispatch expiry event\n dispatchConcordiumEvent({\n type: 'qr-code-expired',\n source: 'desktop',\n modalType: 'scan',\n data: {\n connectionMode,\n isMerchantProvided,\n autoRefresh: isMerchantProvided ? false : autoRefresh,\n },\n });\n\n if (isMerchantProvided) {\n // Merchant-provided QR code expired - notify merchant, don't auto-refresh\n showQRExpiredMessage(false);\n } else if (autoRefresh) {\n // SDK-managed QR code with auto-refresh enabled\n showQRRefreshing();\n await refreshQRCode();\n } else {\n // SDK-managed but auto-refresh disabled\n showQRExpiredMessage(true);\n }\n}\n\n/**\n * Refreshes the QR code (SDK-managed only)\n */\nasync function refreshQRCode(): Promise<void> {\n try {\n // Re-initialize SDK-managed connection to get new URI\n await initializeSDKManagedConnection();\n\n // Dispatch refresh event\n dispatchConcordiumEvent({\n type: 'qr-code-refreshed',\n source: 'desktop',\n modalType: 'scan',\n data: {\n timestamp: Date.now(),\n },\n });\n } catch (error) {\n console.error('Failed to refresh QR code:', error);\n showQRError('Failed to refresh QR code. Please try again.');\n }\n}\n\n/**\n * Shows QR expired message with optional manual refresh button\n */\nfunction showQRExpiredMessage(canRefresh: boolean): void {\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n if (qrContainer) {\n const refreshButtonHTML = canRefresh\n ? `<button id=\"refresh-qr\" class=\"mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm\">\n Refresh QR Code\n </button>`\n : `<p class=\"text-sm text-inverse-tertiary mt-2\">Waiting for new QR code from merchant...</p>`;\n\n qrContainer.innerHTML = `\n <div class=\"text-center\" style=\"min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;\">\n <div class=\"w-48 h-48 bg-yellow-50 border-2 border-yellow-200 rounded flex items-center justify-center mx-auto mb-2\">\n <svg class=\"w-16 h-16 text-yellow-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n </div>\n <p class=\"text-sm text-yellow-600 font-semibold\">QR Code Expired</p>\n ${refreshButtonHTML}\n </div>\n `;\n\n // Add manual refresh functionality\n if (canRefresh) {\n const refreshBtn = qrContainer.querySelector('#refresh-qr');\n if (refreshBtn) {\n refreshBtn.addEventListener('click', async () => {\n showQRRefreshing();\n await refreshQRCode();\n });\n }\n }\n }\n}\n\n/**\n * Shows QR refreshing loading state\n */\nfunction showQRRefreshing(): void {\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n if (qrContainer) {\n qrContainer.innerHTML = `\n <div class=\"animate-pulse text-center\" style=\"min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2 mx-auto\"></div>\n <p class=\"text-sm text-inverse-tertiary\">Refreshing QR code...</p>\n </div>\n `;\n }\n}\n\n/**\n * Updates QR code from merchant-provided URI\n * Called when merchant provides a new URI after expiry\n * @param newUri - The new WalletConnect URI from merchant\n */\nexport async function updateQRCodeFromMerchant(newUri: string): Promise<void> {\n // Display the new QR code\n await displayQRCode(newUri);\n\n // Dispatch refresh event\n dispatchConcordiumEvent({\n type: 'qr-code-refreshed',\n source: 'desktop',\n modalType: 'scan',\n data: {\n timestamp: Date.now(),\n source: 'merchant',\n },\n });\n}\n\nfunction showQRError(message: string): void {\n const qrContainer = document.querySelector(SELECTORS.QR_CONTAINER);\n if (qrContainer) {\n qrContainer.innerHTML = `\n <div class=\"text-center\" style=\"min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;\">\n <div class=\"w-48 h-48 bg-red-50 border-2 border-red-200 rounded flex items-center justify-center mx-auto mb-2\">\n <svg class=\"w-16 h-16 text-red-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\"></path>\n </svg>\n </div>\n <p class=\"text-sm text-red-600\">${message}</p>\n <button id=\"retry-qr\" class=\"mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 text-sm\">\n Retry\n </button>\n </div>\n `;\n\n // Add retry functionality\n const retryBtn = qrContainer.querySelector('#retry-qr');\n if (retryBtn) {\n retryBtn.addEventListener('click', async () => {\n // Reset to loading state\n qrContainer.innerHTML = `\n <div class=\"animate-pulse text-center\" style=\"min-height: 350px; display: flex; flex-direction: column; justify-content: center; align-items: center;\">\n <div class=\"w-48 h-48 bg-gray-200 rounded mb-2 mx-auto\"></div>\n <p class=\"text-sm text-inverse-tertiary\">Generating QR code...</p>\n </div>\n `;\n\n // Retry connection\n await initializeWalletConnection();\n });\n }\n }\n}\n\n/**\n * Sets up event listeners for session approval and verification\n */\nfunction setupEventListeners(): void {\n const listeners: Array<() => void> = [];\n\n // Listen for session-approved event to transition to processing modal\n const handleSessionApproved = async (_event: Event) => {\n // Hide scan modal first and wait for it to be removed\n hideScanModal();\n\n // Wait for scan modal to be fully removed from DOM\n await new Promise((resolve) => setTimeout(resolve, 350));\n\n // Transition to processing modal\n const { showProcessingModal } = await import('./processing');\n await showProcessingModal();\n };\n\n // Add event listeners\n window.addEventListener('concordium-event', (event) => {\n const customEvent = event as CustomEvent;\n if (customEvent.detail?.type === 'session-approved') {\n handleSessionApproved(event);\n }\n });\n\n // Store cleanup function\n const cleanup = () => {\n window.removeEventListener('concordium-event', handleSessionApproved);\n };\n\n listeners.push(cleanup);\n (window as any).scanEventListeners = listeners;\n}\n\n/**\n * Checks for active WalletConnect sessions\n * @returns Session data if there are active sessions, null otherwise\n */\nasync function checkForActiveSession(): Promise<any | null> {\n try {\n const { ServiceFactory } = await import('@/services');\n const walletConnectService = ServiceFactory.createWalletConnectService();\n\n await walletConnectService.initialize();\n const activeSessions = walletConnectService.getActiveSessions();\n\n if (activeSessions.length > 0) {\n // Return the first active session data\n return activeSessions[0];\n }\n\n return null;\n } catch (error) {\n console.error('Failed to check for active sessions:', error);\n return null;\n }\n}\n\n/**\n * Generates deep link for mobile wallets\n * @param walletType - The wallet type (concordium-wallet or concordium-id)\n * @param uri - The WalletConnect URI\n * @returns The deep link URL\n */\nfunction generateDeepLink(walletType: WalletTypeValues, uri: string): string | null {\n const network = localStorage.getItem(ModalConstants.LOCAL_STORAGE_FLAGS.SDK_NETWORK) || 'testnet';\n const ua = navigator.userAgent;\n let deepLink: string | null = null;\n\n if (walletType === WALLET_TYPES.CONCORDIUM_WALLET) {\n // Check device type for Concordium Wallet\n if (/iPad|iPhone|iPod/.test(ua) && !(window as any).MSStream) {\n // iOS\n deepLink = `cryptox${network}://wc?uri=${encodeURIComponent(uri)}&redirect=googlechrome://`;\n } else if (/android/i.test(ua)) {\n // Android\n deepLink = `cryptox-wc-${network}://wc?uri=${encodeURIComponent(uri)}&go_back=true`;\n }\n } else if (walletType === WALLET_TYPES.CONCORDIUM_ID) {\n // Concordium ID - same for all devices, with redirect to origin\n const redirectUrl = encodeURIComponent(window.location.href);\n deepLink = `concordiumidapp://wc?uri=${encodeURIComponent(uri)}&redirect=${redirectUrl}`;\n }\n\n return deepLink;\n}\n\n/**\n * Displays QR code on mobile (when user chooses to verify on another device)\n * @param uri - The WalletConnect URI\n * @param container - The container element to display QR code in\n */\nasync function displayQRCodeMobile(uri: string, container: HTMLElement): Promise<void> {\n try {\n const { default: QRCode } = await import('qrcode');\n const { buildQrRedirectUrl } = await import('@/constants/wallet.registry');\n\n // Use redirect URL for better wallet compatibility\n const qrValue = buildQrRedirectUrl(uri);\n\n const qrCodeDataURL = await QRCode.toDataURL(qrValue, {\n width: 200,\n margin: 2,\n color: { dark: '#000000', light: '#ffffff' },\n });\n\n container.innerHTML = `\n <div class=\"text-center py-4\">\n <img src=\"${qrCodeDataURL}\" alt=\"QR Code for wallet connection\" class=\"w-48 h-48 mx-auto mb-2\" style=\"border-radius: 12.414px; border: 1px solid rgba(0, 0, 0, 0.10); background: #FFF;\" />\n <p class=\"desktop--scan-text\">Scan the QR code with your<br>Concordium ID compatible device</p>\n <img src=\"${sectionSeparator}\" alt=\"\" class=\"mx-auto mt-4\" />\n <div class=\"flex items-center justify-center mt-4\">\n <p class=\"desktop--download-text\">Download & Install the <a href=\"#\">Concordium ID App</a> and come back here to verify.</p>\n </div>\n </div>\n `;\n\n // Show the container\n container.classList.remove(CSS_CLASSES.HIDDEN);\n container.style.display = 'flex';\n } catch (error) {\n console.error('[Mobile] Failed to generate QR code:', error);\n }\n}\n"],"names":["ServiceFactory"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { WalletInfo } from '../../constants/wallet.registry';
|
|
2
|
+
import { HideModalFunction, ModalFunction, ShowModalFunction } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Handle QR redirect on page load
|
|
5
|
+
* When user scans QR code on mobile, they land on this page with uri param
|
|
6
|
+
*/
|
|
7
|
+
export declare function handleQrRedirectOnLoad(): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Detects installed wallets on the device
|
|
10
|
+
* Android: Uses visibility detection
|
|
11
|
+
* iOS: Shows manual selection (can't detect installed apps)
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectInstalledWallets(): Promise<WalletInfo[]>;
|
|
14
|
+
export declare const createWalletSelectionModal: ModalFunction;
|
|
15
|
+
export declare const showWalletSelectionModal: ShowModalFunction;
|
|
16
|
+
export declare const hideWalletSelectionModal: HideModalFunction;
|
|
17
|
+
/**
|
|
18
|
+
* Clear wallet detection cache
|
|
19
|
+
*/
|
|
20
|
+
export declare function clearWalletDetectionCache(): void;
|