@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.
Files changed (41) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/assets/appstore-icon.svg.js +5 -0
  3. package/dist/assets/appstore-icon.svg.js.map +1 -0
  4. package/dist/assets/playstore-icon.svg.js +5 -0
  5. package/dist/assets/playstore-icon.svg.js.map +1 -0
  6. package/dist/components/desktop/landing.js +122 -5
  7. package/dist/components/desktop/landing.js.map +1 -1
  8. package/dist/components/desktop/processing.js +6 -1
  9. package/dist/components/desktop/processing.js.map +1 -1
  10. package/dist/components/desktop/returning-user.js +3 -2
  11. package/dist/components/desktop/returning-user.js.map +1 -1
  12. package/dist/components/desktop/scan.d.ts +6 -3
  13. package/dist/components/desktop/scan.js +116 -12
  14. package/dist/components/desktop/scan.js.map +1 -1
  15. package/dist/components/desktop/wallet-selection.d.ts +20 -0
  16. package/dist/components/desktop/wallet-selection.js +423 -0
  17. package/dist/components/desktop/wallet-selection.js.map +1 -0
  18. package/dist/constants/modal.constants.d.ts +2 -0
  19. package/dist/constants/modal.constants.js +3 -1
  20. package/dist/constants/modal.constants.js.map +1 -1
  21. package/dist/constants/popup.constants.d.ts +2 -2
  22. package/dist/constants/wallet.registry.d.ts +61 -0
  23. package/dist/constants/wallet.registry.js +129 -0
  24. package/dist/constants/wallet.registry.js.map +1 -0
  25. package/dist/constants/walletconnect.constants.d.ts +3 -0
  26. package/dist/constants/walletconnect.constants.js +14 -1
  27. package/dist/constants/walletconnect.constants.js.map +1 -1
  28. package/dist/index.js +7 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/sdk.d.ts +17 -0
  31. package/dist/sdk.js +52 -10
  32. package/dist/sdk.js.map +1 -1
  33. package/dist/services/walletconnect.service.d.ts +10 -0
  34. package/dist/services/walletconnect.service.js +34 -0
  35. package/dist/services/walletconnect.service.js.map +1 -1
  36. package/dist/types/index.d.ts +5 -0
  37. package/dist/utils/mobileAppDetection.d.ts +13 -0
  38. package/dist/utils/mobileAppDetection.js +7 -3
  39. package/dist/utils/mobileAppDetection.js.map +1 -1
  40. package/dist/verification-web-ui.css +1 -1
  41. 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-h-[200px]">
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: [WalletConnectConstants.METHODS.REQUEST_VERIFIABLE_PRESENTATION_V1],
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 qrCodeDataURL = await QRCode.toDataURL(uri, {
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="#">Concordium ID App</a> and come back here to verify.</p>
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 qrCodeDataURL = await QRCode.toDataURL(uri, {
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;