Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: deeplinks handling when lock method is enabled #1034

Merged
merged 2 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -472,17 +472,32 @@ export default () => {
dispatch(AppActions.showBiometricModal({}));
}

if (onboardingCompleted) {
const getBrazeInitialUrl = async (): Promise<string> =>
new Promise(resolve =>
Braze.getInitialURL(deepLink => resolve(deepLink)),
const urlHandler = async () => {
if (onboardingCompleted) {
const getBrazeInitialUrl = async (): Promise<string> =>
new Promise(resolve =>
Braze.getInitialURL(deepLink => resolve(deepLink)),
);
const [url, brazeUrl] = await Promise.all([
Linking.getInitialURL(),
getBrazeInitialUrl(),
]);
await sleep(10);
urlEventHandler({url: url || brazeUrl});
}
};

if (pinLockActive || biometricLockActive) {
const subscriptionToPinModalDismissed =
DeviceEventEmitter.addListener(
DeviceEmitterEvents.APP_LOCK_MODAL_DISMISSED,
() => {
subscriptionToPinModalDismissed.remove();
urlHandler();
},
);
const [url, brazeUrl] = await Promise.all([
Linking.getInitialURL(),
getBrazeInitialUrl(),
]);
await sleep(10);
urlEventHandler({url: url || brazeUrl});
} else {
urlHandler();
}

dispatch(LogActions.info('QuickActions Initialized'));
Expand Down
9 changes: 8 additions & 1 deletion src/components/modal/biometric/BiometricModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import TouchID from 'react-native-touch-id-ng';
import styled from 'styled-components/native';
import {BaseText} from '../../styled/Text';
import BitpaySvg from '../../../../assets/img/wallet/transactions/bitpay.svg';
import {Animated, TouchableOpacity, NativeModules} from 'react-native';
import {
Animated,
TouchableOpacity,
NativeModules,
DeviceEventEmitter,
} from 'react-native';
import {
TO_HANDLE_ERRORS,
BiometricError,
Expand All @@ -25,6 +30,7 @@ import {
import {LOCK_AUTHORIZED_TIME} from '../../../constants/Lock';
import {showBottomNotificationModal} from '../../../store/app/app.actions';
import {useTranslation} from 'react-i18next';
import {DeviceEmitterEvents} from '../../../constants/device-emitter-events';

const BiometricContainer = styled.View`
flex: 1;
Expand Down Expand Up @@ -125,6 +131,7 @@ const BiometricModal: React.FC = () => {
dispatch(AppActions.dismissBiometricModal());
dispatch(AppActions.showBlur(false));
onClose?.(true);
DeviceEventEmitter.emit(DeviceEmitterEvents.APP_LOCK_MODAL_DISMISSED);
})
.catch((error: BiometricError) => {
if (error.code && TO_HANDLE_ERRORS[error.code]) {
Expand Down
10 changes: 9 additions & 1 deletion src/components/modal/pin/PinModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import {useNavigation} from '@react-navigation/native';
import isEqual from 'lodash.isequal';
import React, {useState, useEffect, useCallback, useRef} from 'react';
import {useTranslation} from 'react-i18next';
import {Animated, TouchableOpacity, View, NativeModules} from 'react-native';
import {
Animated,
DeviceEventEmitter,
TouchableOpacity,
View,
NativeModules,
} from 'react-native';
import {gestureHandlerRootHOC} from 'react-native-gesture-handler';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import styled, {useTheme} from 'styled-components/native';
import BitPayLogo from '../../../../assets/img/logos/bitpay-white.svg';
import VirtualKeyboard from '../../../components/virtual-keyboard/VirtualKeyboard';
import {DeviceEmitterEvents} from '../../../constants/device-emitter-events';
import {LOCK_AUTHORIZED_TIME} from '../../../constants/Lock';
import {BwcProvider} from '../../../lib/bwc';
import {AppActions} from '../../../store/app';
Expand Down Expand Up @@ -126,6 +133,7 @@ const Pin = gestureHandlerRootHOC(() => {
dispatch(AppActions.dismissPinModal()); // Correct PIN dismiss modal
reset();
onClose?.(true);
DeviceEventEmitter.emit(DeviceEmitterEvents.APP_LOCK_MODAL_DISMISSED);
} else {
setShakeDots(true);
setMessage(t('Incorrect PIN, try again'));
Expand Down
5 changes: 5 additions & 0 deletions src/constants/device-emitter-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export enum DeviceEmitterEvents {
*/
APP_INIT_COMPLETED = 'APP_INIT_COMPLETED',

/**
* Triggered when the PIN/Biometric modal is dismissed and app is ready to continue with pending tasks.
*/
APP_LOCK_MODAL_DISMISSED = 'APP_LOCK_MODAL_DISMISSED',

/**
* Triggered when the user has completed app onboarding.
*/
Expand Down
71 changes: 56 additions & 15 deletions src/utils/hooks/useDeeplinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
PathConfig,
} from '@react-navigation/native';
import {useMemo, useRef} from 'react';
import {Linking} from 'react-native';
import {DeviceEventEmitter, Linking, NativeModules} from 'react-native';
import AppsFlyer from 'react-native-appsflyer';
import InAppBrowser from 'react-native-inappbrowser-reborn';
import {
Expand All @@ -27,6 +27,8 @@ import useAppDispatch from './useAppDispatch';
import {useLogger} from './useLogger';
import {DebugScreens} from '../../navigation/Debug';
import {GiftCardScreens} from '../../navigation/tabs/shop/gift-card/GiftCardGroup';
import useAppSelector from './useAppSelector';
import {DeviceEmitterEvents} from '../../constants/device-emitter-events';

const getLinkingConfig = (): LinkingOptions<RootStackParamList>['config'] => ({
initialRouteName: RootStacks.TABS,
Expand Down Expand Up @@ -142,30 +144,63 @@ export const useUrlEventHandler = () => {
export const useDeeplinks = () => {
const urlEventHandler = useUrlEventHandler();
const logger = useLogger();
const {biometricLockActive, pinLockActive, lockAuthorizedUntil} =
useAppSelector(({APP}) => APP);

const memoizedSubscribe = useMemo<
LinkingOptions<RootStackParamList>['subscribe']
>(
() => listener => {
const subscription = Linking.addEventListener('url', async ({url}) => {
let handled = false;
const urlObj = new URL(url);
const urlParams = urlObj.searchParams;
const handleUrl = async () => {
const urlObj = new URL(url);
const urlParams = urlObj.searchParams;

if (!handled) {
const isAppsFlyerDeeplink = urlParams.get('af_deeplink') === 'true';
const hasEmbeddedDeepLink = !!urlParams.get('deep_link_value');
if (!handled) {
const isAppsFlyerDeeplink = urlParams.get('af_deeplink') === 'true';
const hasEmbeddedDeepLink = !!urlParams.get('deep_link_value');

// true if should be handled by AppsFlyer SDK
handled = !!(isAppsFlyerDeeplink && hasEmbeddedDeepLink);
}
// true if should be handled by AppsFlyer SDK
handled = !!(isAppsFlyerDeeplink && hasEmbeddedDeepLink);
}

if (!handled) {
handled = !!(await urlEventHandler({url}));
}
if (!handled) {
handled = !!(await urlEventHandler({url}));
}

if (!handled) {
listener(url);
if (!handled) {
listener(url);
}
};

if (pinLockActive || biometricLockActive) {
if (lockAuthorizedUntil) {
const timeSinceBoot = await NativeModules.Timer.getRelativeTime();
const totalSecs =
Number(lockAuthorizedUntil) - Number(timeSinceBoot);
if (totalSecs < 0) {
const subscription = DeviceEventEmitter.addListener(
DeviceEmitterEvents.APP_LOCK_MODAL_DISMISSED,
() => {
subscription.remove();
handleUrl();
},
);
} else {
handleUrl();
}
} else {
const subscription = DeviceEventEmitter.addListener(
DeviceEmitterEvents.APP_LOCK_MODAL_DISMISSED,
() => {
subscription.remove();
handleUrl();
},
);
}
} else {
handleUrl();
}
});

Expand Down Expand Up @@ -217,7 +252,13 @@ export const useDeeplinks = () => {
appsFlyerUnsubscribe();
};
},
[logger, urlEventHandler],
[
logger,
urlEventHandler,
pinLockActive,
biometricLockActive,
lockAuthorizedUntil,
],
);

const linkingOptions: LinkingOptions<RootStackParamList> = {
Expand Down