@volr/react-ui 0.1.119 → 0.1.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -61,6 +61,7 @@ declare const VolrUIProvider: React$1.FC<VolrUIProviderProps>;
61
61
  /**
62
62
  * Passkey Enrollment View Component
63
63
  * Modern passkey setup with device-specific biometric icons
64
+ * Includes cross-domain migration detection and guidance
64
65
  */
65
66
  interface PasskeyEnrollViewProps {
66
67
  onComplete: () => void;
@@ -151,6 +152,7 @@ declare const en: {
151
152
  readonly titleTouchId: "Set up Touch ID login";
152
153
  readonly titleFaceId: "Set up Face ID login";
153
154
  readonly titleFingerprint: "Set up fingerprint login";
155
+ readonly titleQrCode: "Set up mobile login";
154
156
  readonly description: "Sign in instantly, every time.";
155
157
  readonly touchId: "Use Touch ID to create your passkey";
156
158
  readonly faceId: "Use Face ID to create your passkey";
@@ -178,6 +180,7 @@ declare const en: {
178
180
  readonly outdatedSamsung: "Please update Samsung Internet to the latest version.";
179
181
  readonly outdatedIOS: "iOS 17.4 or later is required. Please check for software updates in Settings.";
180
182
  readonly firefoxNotSupported: "Secure login is not available in Firefox. Please use Chrome or Safari.";
183
+ readonly whaleNotSupported: "Secure login is not available in Whale browser. Please use Chrome.";
181
184
  readonly unknownBrowser: "Secure login may not work properly in this browser.";
182
185
  readonly openInExternalBrowser: "Open in external browser";
183
186
  readonly updateBrowser: "Update browser";
@@ -192,6 +195,19 @@ declare const en: {
192
195
  readonly default: "Please use this device's biometric.";
193
196
  readonly note: "Using other devices or apps may not work.";
194
197
  };
198
+ readonly migration: {
199
+ readonly title: "Set up passkey for this site";
200
+ readonly description: "Your wallet was created on {{sourceDomain}}. To use it here, you need to set up a new passkey for this site.";
201
+ readonly descriptionGeneric: "Your wallet was created on a different site. To use it here, you need to set up a new passkey for this site.";
202
+ readonly currentDomain: "Current site";
203
+ readonly sourceDomain: "Original site";
204
+ readonly benefits: "Your wallet address and balance will remain the same.";
205
+ readonly cta: "Set up passkey";
206
+ readonly later: "Do it later";
207
+ readonly inProgress: "Setting up...";
208
+ readonly success: "Passkey set up successfully!";
209
+ readonly error: "Failed to set up passkey. Please try again.";
210
+ };
195
211
  };
196
212
  readonly success: {
197
213
  readonly title: "Success!";
package/dist/index.d.ts CHANGED
@@ -61,6 +61,7 @@ declare const VolrUIProvider: React$1.FC<VolrUIProviderProps>;
61
61
  /**
62
62
  * Passkey Enrollment View Component
63
63
  * Modern passkey setup with device-specific biometric icons
64
+ * Includes cross-domain migration detection and guidance
64
65
  */
65
66
  interface PasskeyEnrollViewProps {
66
67
  onComplete: () => void;
@@ -151,6 +152,7 @@ declare const en: {
151
152
  readonly titleTouchId: "Set up Touch ID login";
152
153
  readonly titleFaceId: "Set up Face ID login";
153
154
  readonly titleFingerprint: "Set up fingerprint login";
155
+ readonly titleQrCode: "Set up mobile login";
154
156
  readonly description: "Sign in instantly, every time.";
155
157
  readonly touchId: "Use Touch ID to create your passkey";
156
158
  readonly faceId: "Use Face ID to create your passkey";
@@ -178,6 +180,7 @@ declare const en: {
178
180
  readonly outdatedSamsung: "Please update Samsung Internet to the latest version.";
179
181
  readonly outdatedIOS: "iOS 17.4 or later is required. Please check for software updates in Settings.";
180
182
  readonly firefoxNotSupported: "Secure login is not available in Firefox. Please use Chrome or Safari.";
183
+ readonly whaleNotSupported: "Secure login is not available in Whale browser. Please use Chrome.";
181
184
  readonly unknownBrowser: "Secure login may not work properly in this browser.";
182
185
  readonly openInExternalBrowser: "Open in external browser";
183
186
  readonly updateBrowser: "Update browser";
@@ -192,6 +195,19 @@ declare const en: {
192
195
  readonly default: "Please use this device's biometric.";
193
196
  readonly note: "Using other devices or apps may not work.";
194
197
  };
198
+ readonly migration: {
199
+ readonly title: "Set up passkey for this site";
200
+ readonly description: "Your wallet was created on {{sourceDomain}}. To use it here, you need to set up a new passkey for this site.";
201
+ readonly descriptionGeneric: "Your wallet was created on a different site. To use it here, you need to set up a new passkey for this site.";
202
+ readonly currentDomain: "Current site";
203
+ readonly sourceDomain: "Original site";
204
+ readonly benefits: "Your wallet address and balance will remain the same.";
205
+ readonly cta: "Set up passkey";
206
+ readonly later: "Do it later";
207
+ readonly inProgress: "Setting up...";
208
+ readonly success: "Passkey set up successfully!";
209
+ readonly error: "Failed to set up passkey. Please try again.";
210
+ };
195
211
  };
196
212
  readonly success: {
197
213
  readonly title: "Success!";
package/dist/index.js CHANGED
@@ -526,6 +526,7 @@ var en = {
526
526
  titleTouchId: "Set up Touch ID login",
527
527
  titleFaceId: "Set up Face ID login",
528
528
  titleFingerprint: "Set up fingerprint login",
529
+ titleQrCode: "Set up mobile login",
529
530
  // Short description
530
531
  description: "Sign in instantly, every time.",
531
532
  // Legacy keys for backward compatibility
@@ -555,6 +556,7 @@ var en = {
555
556
  outdatedSamsung: "Please update Samsung Internet to the latest version.",
556
557
  outdatedIOS: "iOS 17.4 or later is required. Please check for software updates in Settings.",
557
558
  firefoxNotSupported: "Secure login is not available in Firefox. Please use Chrome or Safari.",
559
+ whaleNotSupported: "Secure login is not available in Whale browser. Please use Chrome.",
558
560
  unknownBrowser: "Secure login may not work properly in this browser.",
559
561
  openInExternalBrowser: "Open in external browser",
560
562
  updateBrowser: "Update browser",
@@ -568,6 +570,19 @@ var en = {
568
570
  windows: "Please use your phone via QR code. (Windows Hello is not supported)",
569
571
  default: "Please use this device's biometric.",
570
572
  note: "Using other devices or apps may not work."
573
+ },
574
+ migration: {
575
+ title: "Set up passkey for this site",
576
+ description: "Your wallet was created on {{sourceDomain}}. To use it here, you need to set up a new passkey for this site.",
577
+ descriptionGeneric: "Your wallet was created on a different site. To use it here, you need to set up a new passkey for this site.",
578
+ currentDomain: "Current site",
579
+ sourceDomain: "Original site",
580
+ benefits: "Your wallet address and balance will remain the same.",
581
+ cta: "Set up passkey",
582
+ later: "Do it later",
583
+ inProgress: "Setting up...",
584
+ success: "Passkey set up successfully!",
585
+ error: "Failed to set up passkey. Please try again."
571
586
  }
572
587
  },
573
588
  success: {
@@ -753,6 +768,7 @@ var ko = {
753
768
  titleTouchId: "Touch ID \uB85C\uADF8\uC778 \uC124\uC815",
754
769
  titleFaceId: "Face ID \uB85C\uADF8\uC778 \uC124\uC815",
755
770
  titleFingerprint: "\uC9C0\uBB38 \uB85C\uADF8\uC778 \uC124\uC815",
771
+ titleQrCode: "\uD734\uB300\uD3F0\uC73C\uB85C \uB85C\uADF8\uC778 \uC124\uC815",
756
772
  // Short description
757
773
  description: "\uD55C \uBC88 \uB4F1\uB85D\uD558\uBA74, \uB2E4\uC74C\uBD80\uD130 \uBC14\uB85C \uB85C\uADF8\uC778",
758
774
  // Legacy keys for backward compatibility
@@ -782,6 +798,7 @@ var ko = {
782
798
  outdatedSamsung: "Samsung Internet\uC744 \uCD5C\uC2E0 \uBC84\uC804\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD574\uC8FC\uC138\uC694.",
783
799
  outdatedIOS: "iOS 17.4 \uC774\uC0C1 \uBC84\uC804\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uC124\uC815\uC5D0\uC11C \uC18C\uD504\uD2B8\uC6E8\uC5B4 \uC5C5\uB370\uC774\uD2B8\uB97C \uD655\uC778\uD574\uC8FC\uC138\uC694.",
784
800
  firefoxNotSupported: "Firefox\uC5D0\uC11C\uB294 \uBCF4\uC548 \uB85C\uADF8\uC778\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. Chrome \uB610\uB294 Safari\uB97C \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.",
801
+ whaleNotSupported: "\uC6E8\uC77C \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C\uB294 \uBCF4\uC548 \uB85C\uADF8\uC778\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. Chrome\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.",
785
802
  unknownBrowser: "\uC774 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C\uB294 \uBCF4\uC548 \uB85C\uADF8\uC778\uC774 \uC81C\uB300\uB85C \uC791\uB3D9\uD558\uC9C0 \uC54A\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
786
803
  openInExternalBrowser: "\uC678\uBD80 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uAE30",
787
804
  updateBrowser: "\uBE0C\uB77C\uC6B0\uC800 \uC5C5\uB370\uC774\uD2B8",
@@ -795,6 +812,19 @@ var ko = {
795
812
  windows: "QR \uCF54\uB4DC\uB85C \uD734\uB300\uD3F0\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694. (Windows Hello\uB294 \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4)",
796
813
  default: "\uC774 \uAE30\uAE30\uC758 \uC0DD\uCCB4 \uC778\uC99D\uC744 \uC0AC\uC6A9\uD574\uC8FC\uC138\uC694.",
797
814
  note: "\uB2E4\uB978 \uAE30\uAE30\uB098 \uC571 \uC0AC\uC6A9 \uC2DC \uB3D9\uC791\uD558\uC9C0 \uC54A\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
815
+ },
816
+ migration: {
817
+ title: "\uC774 \uC0AC\uC774\uD2B8\uC6A9 \uD328\uC2A4\uD0A4 \uC124\uC815",
818
+ description: "\uC9C0\uAC11\uC774 {{sourceDomain}}\uC5D0\uC11C \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774 \uC0AC\uC774\uD2B8\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB824\uBA74 \uC0C8 \uD328\uC2A4\uD0A4\uB97C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.",
819
+ descriptionGeneric: "\uC9C0\uAC11\uC774 \uB2E4\uB978 \uC0AC\uC774\uD2B8\uC5D0\uC11C \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774 \uC0AC\uC774\uD2B8\uC5D0\uC11C \uC0AC\uC6A9\uD558\uB824\uBA74 \uC0C8 \uD328\uC2A4\uD0A4\uB97C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.",
820
+ currentDomain: "\uD604\uC7AC \uC0AC\uC774\uD2B8",
821
+ sourceDomain: "\uC6D0\uBCF8 \uC0AC\uC774\uD2B8",
822
+ benefits: "\uC9C0\uAC11 \uC8FC\uC18C\uC640 \uC794\uC561\uC740 \uADF8\uB300\uB85C \uC720\uC9C0\uB429\uB2C8\uB2E4.",
823
+ cta: "\uD328\uC2A4\uD0A4 \uC124\uC815\uD558\uAE30",
824
+ later: "\uB098\uC911\uC5D0 \uD558\uAE30",
825
+ inProgress: "\uC124\uC815 \uC911...",
826
+ success: "\uD328\uC2A4\uD0A4 \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!",
827
+ error: "\uD328\uC2A4\uD0A4 \uC124\uC815\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694."
798
828
  }
799
829
  },
800
830
  success: {
@@ -1366,13 +1396,21 @@ var ModalHeader = ({
1366
1396
 
1367
1397
  // src/components/features/passkey/utils/biometric.ts
1368
1398
  function getBiometricType() {
1399
+ if (typeof navigator === "undefined") return "fingerprint";
1369
1400
  const ua = navigator.userAgent;
1401
+ const platform = navigator.platform || "";
1370
1402
  if (/iPhone|iPad|iPod/.test(ua)) {
1371
1403
  return "faceId";
1372
1404
  }
1373
1405
  if (/Macintosh|MacIntel/.test(ua)) {
1406
+ if (navigator.maxTouchPoints > 1) {
1407
+ return "faceId";
1408
+ }
1374
1409
  return "touchId";
1375
1410
  }
1411
+ if (/Win/.test(platform)) {
1412
+ return "qrCode";
1413
+ }
1376
1414
  return "fingerprint";
1377
1415
  }
1378
1416
  function getUserFriendlyError(error, t) {
@@ -1620,12 +1658,44 @@ function FingerprintIcon({ size }) {
1620
1658
  }
1621
1659
  );
1622
1660
  }
1661
+ function QrCodeIcon({ size }) {
1662
+ const fill = "#f87171";
1663
+ return /* @__PURE__ */ jsxs(
1664
+ "svg",
1665
+ {
1666
+ width: size,
1667
+ height: size,
1668
+ viewBox: "0 0 24 24",
1669
+ fill: "none",
1670
+ xmlns: "http://www.w3.org/2000/svg",
1671
+ children: [
1672
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1", fill }),
1673
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1", fill }),
1674
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1", fill }),
1675
+ /* @__PURE__ */ jsx("rect", { x: "5", y: "5", width: "3", height: "3", fill: "white" }),
1676
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "5", width: "3", height: "3", fill: "white" }),
1677
+ /* @__PURE__ */ jsx("rect", { x: "5", y: "16", width: "3", height: "3", fill: "white" }),
1678
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "14", width: "2", height: "2", fill }),
1679
+ /* @__PURE__ */ jsx("rect", { x: "17", y: "14", width: "2", height: "2", fill }),
1680
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "17", width: "2", height: "2", fill }),
1681
+ /* @__PURE__ */ jsx("rect", { x: "19", y: "17", width: "2", height: "2", fill }),
1682
+ /* @__PURE__ */ jsx("rect", { x: "17", y: "19", width: "2", height: "2", fill }),
1683
+ /* @__PURE__ */ jsx("rect", { x: "11", y: "3", width: "2", height: "2", fill }),
1684
+ /* @__PURE__ */ jsx("rect", { x: "11", y: "6", width: "2", height: "2", fill }),
1685
+ /* @__PURE__ */ jsx("rect", { x: "11", y: "11", width: "2", height: "2", fill }),
1686
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "11", width: "2", height: "2", fill }),
1687
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "11", width: "2", height: "2", fill })
1688
+ ]
1689
+ }
1690
+ );
1691
+ }
1623
1692
  function BiometricIcon({ type, size = 80, animate = false }) {
1624
1693
  const className = animate ? "volr:animate-pulse" : "";
1625
1694
  return /* @__PURE__ */ jsxs("div", { className, children: [
1626
1695
  type === "faceId" && /* @__PURE__ */ jsx(FaceIdIcon, { size }),
1627
1696
  type === "touchId" && /* @__PURE__ */ jsx(TouchIdIcon, { size }),
1628
- type === "fingerprint" && /* @__PURE__ */ jsx(FingerprintIcon, { size })
1697
+ type === "fingerprint" && /* @__PURE__ */ jsx(FingerprintIcon, { size }),
1698
+ type === "qrCode" && /* @__PURE__ */ jsx(QrCodeIcon, { size })
1629
1699
  ] });
1630
1700
  }
1631
1701
  var sizeMap = {
@@ -1814,6 +1884,84 @@ function PasskeyCompatibilityScreen({
1814
1884
  ] })
1815
1885
  ] });
1816
1886
  }
1887
+ function PasskeyMigrationView({
1888
+ sourcePasskey,
1889
+ currentDomain,
1890
+ onMigrate,
1891
+ onSkip,
1892
+ onError,
1893
+ isOpen = true,
1894
+ wrapInModal = true
1895
+ }) {
1896
+ const { t } = useI18n();
1897
+ const [isMigrating, setIsMigrating] = useState(false);
1898
+ const [error, setError] = useState(null);
1899
+ const biometricType = getBiometricType();
1900
+ const handleMigrate = async () => {
1901
+ try {
1902
+ setIsMigrating(true);
1903
+ setError(null);
1904
+ await onMigrate();
1905
+ } catch (err) {
1906
+ const errorMessage = err instanceof Error ? err.message : String(err);
1907
+ setError(t("passkey.migration.error"));
1908
+ if (onError) {
1909
+ onError(err instanceof Error ? err : new Error(errorMessage));
1910
+ }
1911
+ } finally {
1912
+ setIsMigrating(false);
1913
+ }
1914
+ };
1915
+ const content = /* @__PURE__ */ jsxs("div", { children: [
1916
+ /* @__PURE__ */ jsx("p", { className: "volr:text-xl volr:font-semibold volr:mb-4", children: t("passkey.migration.title") }),
1917
+ /* @__PURE__ */ jsx("div", { className: "volr:my-6 volr:flex volr:justify-center", children: /* @__PURE__ */ jsx(BiometricIcon, { type: biometricType, size: 48 }) }),
1918
+ /* @__PURE__ */ jsx("p", { className: "volr:text-sm volr:mb-4 volr:text-center volr-text-secondary", children: sourcePasskey.rpId ? t("passkey.migration.description").replace(
1919
+ "{{sourceDomain}}",
1920
+ sourcePasskey.rpId
1921
+ ) : t("passkey.migration.descriptionGeneric") }),
1922
+ /* @__PURE__ */ jsxs("div", { className: "volr:mb-4 volr:p-3 volr:rounded-lg volr:border volr:border-slate-200 volr:bg-slate-50", children: [
1923
+ /* @__PURE__ */ jsxs("div", { className: "volr:flex volr:justify-between volr:items-center volr:text-sm volr:mb-2", children: [
1924
+ /* @__PURE__ */ jsx("span", { className: "volr-text-secondary", children: t("passkey.migration.sourceDomain") }),
1925
+ /* @__PURE__ */ jsx("span", { className: "volr:font-mono volr:text-xs", children: sourcePasskey.rpId })
1926
+ ] }),
1927
+ /* @__PURE__ */ jsxs("div", { className: "volr:flex volr:justify-between volr:items-center volr:text-sm", children: [
1928
+ /* @__PURE__ */ jsx("span", { className: "volr-text-secondary", children: t("passkey.migration.currentDomain") }),
1929
+ /* @__PURE__ */ jsx("span", { className: "volr:font-mono volr:text-xs", children: currentDomain })
1930
+ ] })
1931
+ ] }),
1932
+ /* @__PURE__ */ jsx("div", { className: "volr:mb-6 volr:p-3 volr:rounded-lg volr-hint", children: /* @__PURE__ */ jsxs("p", { className: "volr:text-sm volr:flex volr:items-start volr:gap-2", children: [
1933
+ /* @__PURE__ */ jsx("span", { className: "volr:text-base", children: "\u2713" }),
1934
+ /* @__PURE__ */ jsx("span", { children: t("passkey.migration.benefits") })
1935
+ ] }) }),
1936
+ error && /* @__PURE__ */ jsx("div", { className: "volr:mb-4 volr:p-3 volr:rounded-lg volr:border volr:text-sm volr:text-left volr-error", children: /* @__PURE__ */ jsx("span", { children: error }) }),
1937
+ /* @__PURE__ */ jsxs("div", { className: "volr:flex volr:flex-col volr:gap-3", children: [
1938
+ /* @__PURE__ */ jsx(
1939
+ Button,
1940
+ {
1941
+ variant: "primary",
1942
+ fullWidth: true,
1943
+ onClick: handleMigrate,
1944
+ disabled: isMigrating,
1945
+ children: isMigrating ? t("passkey.migration.inProgress") : t("passkey.migration.cta")
1946
+ }
1947
+ ),
1948
+ onSkip && /* @__PURE__ */ jsx(
1949
+ Button,
1950
+ {
1951
+ variant: "ghost",
1952
+ fullWidth: true,
1953
+ onClick: onSkip,
1954
+ disabled: isMigrating,
1955
+ children: t("passkey.migration.later")
1956
+ }
1957
+ )
1958
+ ] })
1959
+ ] });
1960
+ if (!wrapInModal) {
1961
+ return content;
1962
+ }
1963
+ return /* @__PURE__ */ jsx(Modal, { open: isOpen, onOpenChange: (open) => !open && onSkip?.(), children: content });
1964
+ }
1817
1965
  function PasskeyEnrollView({
1818
1966
  onComplete,
1819
1967
  onError,
@@ -1842,14 +1990,34 @@ function PasskeyEnrollView({
1842
1990
  [compatibility.platform]
1843
1991
  );
1844
1992
  const hasPasskey = user?.keyStorageType === "passkey";
1993
+ const currentDomain = useMemo(() => {
1994
+ if (typeof window === "undefined") return "localhost";
1995
+ return window.location.hostname;
1996
+ }, []);
1997
+ const migrationInfo = useMemo(() => {
1998
+ if (!user?.registeredPasskeys || user.registeredPasskeys.length === 0) {
1999
+ return { needsMigration: false, sourcePasskey: null };
2000
+ }
2001
+ const hasPasskeyOnCurrentDomain = user.registeredPasskeys.some(
2002
+ (pk) => pk.rpId === currentDomain
2003
+ );
2004
+ if (hasPasskeyOnCurrentDomain) {
2005
+ return { needsMigration: false, sourcePasskey: null };
2006
+ }
2007
+ const sourcePasskey = user.registeredPasskeys[0];
2008
+ return { needsMigration: true, sourcePasskey };
2009
+ }, [user?.registeredPasskeys, currentDomain]);
1845
2010
  useEffect(() => {
1846
2011
  console.log("[PasskeyEnrollView] User state:", {
1847
2012
  user,
1848
2013
  keyStorageType: user?.keyStorageType,
1849
2014
  evmAddress: user?.evmAddress,
1850
- hasPasskey
2015
+ hasPasskey,
2016
+ registeredPasskeys: user?.registeredPasskeys,
2017
+ currentDomain,
2018
+ migrationInfo
1851
2019
  });
1852
- }, [user, hasPasskey]);
2020
+ }, [user, hasPasskey, currentDomain, migrationInfo]);
1853
2021
  useEffect(() => {
1854
2022
  if (hasPasskey && !user?.evmAddress && !isRefreshing) {
1855
2023
  const refreshUserData = async () => {
@@ -1960,13 +2128,16 @@ function PasskeyEnrollView({
1960
2128
  }
1961
2129
  };
1962
2130
  const getBiometricTitle = () => {
1963
- if (biometricType === "faceId") {
1964
- return t("passkey.titleFaceId");
1965
- }
1966
- if (biometricType === "touchId") {
1967
- return t("passkey.titleTouchId");
2131
+ switch (biometricType) {
2132
+ case "faceId":
2133
+ return t("passkey.titleFaceId");
2134
+ case "touchId":
2135
+ return t("passkey.titleTouchId");
2136
+ case "qrCode":
2137
+ return t("passkey.titleQrCode");
2138
+ default:
2139
+ return t("passkey.titleFingerprint");
1968
2140
  }
1969
- return t("passkey.titleFingerprint");
1970
2141
  };
1971
2142
  const getBiometricDescription = () => {
1972
2143
  return t("passkey.description");
@@ -1984,6 +2155,23 @@ function PasskeyEnrollView({
1984
2155
  }
1985
2156
  return /* @__PURE__ */ jsx(Modal, { open: isOpen, onOpenChange: (open) => !open && onLogout?.(), children: compatibilityContent });
1986
2157
  }
2158
+ if (migrationInfo.needsMigration && migrationInfo.sourcePasskey) {
2159
+ const handleMigration = async () => {
2160
+ await handleEnroll();
2161
+ };
2162
+ return /* @__PURE__ */ jsx(
2163
+ PasskeyMigrationView,
2164
+ {
2165
+ sourcePasskey: migrationInfo.sourcePasskey,
2166
+ currentDomain,
2167
+ onMigrate: handleMigration,
2168
+ onSkip: handleLogout,
2169
+ onError,
2170
+ isOpen,
2171
+ wrapInModal
2172
+ }
2173
+ );
2174
+ }
1987
2175
  if (hasPasskey) {
1988
2176
  const handleClose = () => {
1989
2177
  if (onClose) {