diff --git a/app/jest.setup.js b/app/jest.setup.js index f903d00dc..484aac969 100644 --- a/app/jest.setup.js +++ b/app/jest.setup.js @@ -574,7 +574,6 @@ jest.mock('@selfxyz/mobile-sdk-alpha', () => ({ // Override only the specific mocks we need NFCScannerScreen: jest.fn(() => null), SelfClientProvider: jest.fn(({ children }) => children), - useSafeBottomPadding: jest.fn((basePadding = 20) => basePadding + 50), useSelfClient: jest.fn(() => { // Create a consistent mock instance for memoization testing if (!global.mockSelfClientInstance) { diff --git a/app/src/components/proof-request/WalletAddressModal.tsx b/app/src/components/proof-request/WalletAddressModal.tsx index 23309584c..98b4e45d8 100644 --- a/app/src/components/proof-request/WalletAddressModal.tsx +++ b/app/src/components/proof-request/WalletAddressModal.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: BUSL-1.1 // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Modal, Pressable, StyleSheet } from 'react-native'; import { Text, View, XStack, YStack } from 'tamagui'; import Clipboard from '@react-native-clipboard/clipboard'; @@ -32,6 +32,7 @@ export const WalletAddressModal: React.FC = ({ testID = 'wallet-address-modal', }) => { const [copied, setCopied] = useState(false); + const timeoutRef = useRef | null>(null); const label = userIdType === 'hex' ? 'Connected Wallet' : 'Connected ID'; // Reset copied state when modal closes @@ -41,14 +42,31 @@ export const WalletAddressModal: React.FC = ({ } }, [visible]); + // Clear timeout on unmount or when modal closes/address changes + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + }; + }, [visible, address, onClose]); + const handleCopy = useCallback(() => { + // Clear any existing timeout before setting a new one + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + Clipboard.setString(address); setCopied(true); // Reset copied state and close after a brief delay - setTimeout(() => { + timeoutRef.current = setTimeout(() => { setCopied(false); onClose(); + timeoutRef.current = null; }, 800); }, [address, onClose]); diff --git a/app/src/utils/disclosureUtils.ts b/app/src/utils/disclosureUtils.ts index 0bcdf20b2..5c7d923e6 100644 --- a/app/src/utils/disclosureUtils.ts +++ b/app/src/utils/disclosureUtils.ts @@ -8,8 +8,8 @@ import type { SelfAppDisclosureConfig } from '@selfxyz/common/utils/appType'; function listToString(list: string[]): string { if (list.length === 1) return list[0]; - if (list.length === 2) return list.join(' nor '); - return `${list.slice(0, -1).join(', ')} nor ${list.at(-1)}`; + if (list.length === 2) return list.join(' or '); + return `${list.slice(0, -1).join(', ')} or ${list.at(-1)}`; } function countriesToSentence(countries: Country3LetterCode[]): string { diff --git a/app/tests/src/screens/verification/DocumentSelectorForProvingScreen.test.tsx b/app/tests/src/screens/verification/DocumentSelectorForProvingScreen.test.tsx index 3ff3c5d76..1f7006b33 100644 --- a/app/tests/src/screens/verification/DocumentSelectorForProvingScreen.test.tsx +++ b/app/tests/src/screens/verification/DocumentSelectorForProvingScreen.test.tsx @@ -20,26 +20,25 @@ import { usePassport } from '@/providers/passportDataProvider'; import { DocumentSelectorForProvingScreen } from '@/screens/verification/DocumentSelectorForProvingScreen'; // Mock useFocusEffect to behave like useEffect in tests -// Note: We use jest.requireActual for React to avoid nested require() which causes OOM in CI +// Note: We call the callback directly without requiring React to avoid OOM in CI jest.mock('@react-navigation/native', () => { const actual = jest.requireActual('@react-navigation/native'); - const ReactActual = jest.requireActual('react'); return { ...actual, useFocusEffect: (callback: () => void) => { - ReactActual.useEffect(() => { + // Call the callback immediately, simulating focus effect in tests + // We use setTimeout to defer execution similar to useEffect + setTimeout(() => { callback(); - }, [callback]); + }, 0); }, }; }); // Mock the WalletAddressModal to avoid Modal rendering issues in tests +// Note: We return a simple string component directly to avoid requiring React (prevents OOM in CI) jest.mock('@/components/proof-request/WalletAddressModal', () => ({ - WalletAddressModal: ({ testID }: { testID?: string }) => { - const React = jest.requireActual('react'); - return React.createElement('View', { testID }); - }, + WalletAddressModal: jest.fn(() => null), })); jest.mock('@selfxyz/mobile-sdk-alpha', () => ({ diff --git a/packages/mobile-sdk-alpha/src/constants/index.ts b/packages/mobile-sdk-alpha/src/constants/index.ts index e89f90b86..eba2b56b7 100644 --- a/packages/mobile-sdk-alpha/src/constants/index.ts +++ b/packages/mobile-sdk-alpha/src/constants/index.ts @@ -30,6 +30,8 @@ export { cyan300, emerald500, green500, + green600, + iosSeparator, neutral400, neutral700, red500, diff --git a/packages/mobile-sdk-alpha/src/index.ts b/packages/mobile-sdk-alpha/src/index.ts index 631c9d28a..7ebeae490 100644 --- a/packages/mobile-sdk-alpha/src/index.ts +++ b/packages/mobile-sdk-alpha/src/index.ts @@ -99,7 +99,6 @@ export { triggerFeedback, } from './haptic'; -/** @deprecated Use createSelfClient().extractMRZInfo or import from './mrz' */ export { checkDocumentExpiration, getDocumentAttributes, @@ -123,8 +122,10 @@ export { defaultConfig } from './config/defaults'; export { defaultOptions } from './haptic/shared'; -export { extractMRZInfo, extractNameFromMRZ, formatDateToYYMMDD } from './mrz'; +/** @deprecated Use createSelfClient().extractMRZInfo or import from './mrz' */ +export { extractMRZInfo } from './mrz'; export { extractNameFromDocument } from './documents/utils'; +export { extractNameFromMRZ, formatDateToYYMMDD } from './mrz'; export { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm } from './mock/generator';