Skip to content

Commit

Permalink
fix: 🔁 device selection after aborted flow (#7778)
Browse files Browse the repository at this point in the history
* Fix device selection after aborted flow

* Update change log

* Apply the fix to the account creation flow

* Keep the `onClose` handler declaration

---------

Co-authored-by: Theophile Sandoz <Theophile Sandoz>
  • Loading branch information
thesan authored Sep 10, 2024
1 parent 7f53095 commit 8649ebf
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/lemon-starfishes-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"live-mobile": patch
---

Fix device selection after LedgerSync aborted flow
8 changes: 7 additions & 1 deletion apps/ledger-live-mobile/src/components/DeviceActionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SyncSkipUnderPriority } from "@ledgerhq/live-common/bridge/react/index";
import { Action, Device } from "@ledgerhq/live-common/hw/actions/types";
import { Alert, Flex } from "@ledgerhq/native-ui";
import React, { useCallback, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components/native";
import { PartialNullable } from "~/types/helpers";
Expand All @@ -23,6 +23,7 @@ type Props<Req, Stt, Res> = {
renderOnResult?: (_: Res) => JSX.Element | null;
onSelectDeviceLink?: () => void;
analyticsPropertyFlow?: string;
registerDeviceSelection?: (onDeviceUpdated: () => void) => void;
};

export default function DeviceActionModal<Req, Stt, Res>({
Expand All @@ -36,6 +37,7 @@ export default function DeviceActionModal<Req, Stt, Res>({
onModalHide,
onSelectDeviceLink,
analyticsPropertyFlow,
registerDeviceSelection,
}: Props<Req, Stt, Res>) {
const { t } = useTranslation();
const showAlert = !device?.wired;
Expand All @@ -54,6 +56,10 @@ export default function DeviceActionModal<Req, Stt, Res>({
}
}, [onClose, result]);

useEffect(() => {
registerDeviceSelection?.(() => setResult(null));
}, [registerDeviceSelection]);

return (
<QueuedDrawer
isRequestingToBeOpened={result ? false : !!device}
Expand Down
18 changes: 17 additions & 1 deletion apps/ledger-live-mobile/src/hooks/deviceActions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo } from "react";
import { useCallback, useMemo, useRef, useState } from "react";
import { createAction as appCreateAction } from "@ledgerhq/live-common/hw/actions/app";
import { createAction as transactionCreateAction } from "@ledgerhq/live-common/hw/actions/transaction";
import { createAction as startExchangeCreateAction } from "@ledgerhq/live-common/hw/actions/startExchange";
Expand All @@ -11,6 +11,7 @@ import { createAction as staxFetchImageCreateAction } from "@ledgerhq/live-commo
import { createAction as installLanguageCreateAction } from "@ledgerhq/live-common/hw/actions/installLanguage";
import { createAction as staxRemoveImageCreateAction } from "@ledgerhq/live-common/hw/actions/customLockScreenRemove";
import { createAction as renameDeviceCreateAction } from "@ledgerhq/live-common/hw/actions/renameDevice";
import type { Device } from "@ledgerhq/live-common/hw/actions/types";
import renameDevice from "@ledgerhq/live-common/hw/renameDevice";
import customLockScreenLoad from "@ledgerhq/live-common/hw/customLockScreenLoad";
import installLanguage from "@ledgerhq/live-common/hw/installLanguage";
Expand Down Expand Up @@ -124,3 +125,18 @@ export function useRenameDeviceAction() {
[mock],
);
}

export function useSelectDevice() {
const [device, setDevice] = useState<Device | null | undefined>(null);

const onDeviceUpdated = useRef<() => void>();
const registerDeviceSelection = useCallback((handler: () => void) => {
onDeviceUpdated.current = handler;
}, []);
const selectDevice = useCallback((device: Device | null | undefined) => {
setDevice(device);
onDeviceUpdated.current?.();
}, []);

return { device, selectDevice, registerDeviceSelection };
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
ReactNavigationHeaderOptions,
StackNavigatorProps,
} from "~/components/RootNavigator/types/helpers";
import { useAppDeviceAction } from "~/hooks/deviceActions";
import { useAppDeviceAction, useSelectDevice } from "~/hooks/deviceActions";
import { AppResult } from "@ledgerhq/live-common/hw/actions/app";
import { WalletSyncNavigatorStackParamList } from "~/components/RootNavigator/types/WalletSyncNavigator";
import { TRUSTCHAIN_APP_NAME } from "@ledgerhq/hw-trustchain";
Expand Down Expand Up @@ -47,16 +47,12 @@ const WalletSyncActivationDeviceSelection: React.FC<ChooseDeviceProps> = ({
}) => {
const isFocused = useIsFocused();
const action = useAppDeviceAction();
const [device, setDevice] = useState<Device | null>();
const { device, selectDevice, registerDeviceSelection } = useSelectDevice();
const [isHeaderOverridden, setIsHeaderOverridden] = useState<boolean>(false);

const navigation = useNavigation<NavigationProps["navigation"]>();

const onSelectDevice = useCallback((device: Device) => {
setDevice(device);
}, []);

const onClose = () => setDevice(null);
const onClose = () => selectDevice(null);

const onResult = useCallback(
(payload: AppResult) => {
Expand All @@ -71,7 +67,7 @@ const WalletSyncActivationDeviceSelection: React.FC<ChooseDeviceProps> = ({
// and avoids a duplicated error drawers/messages.
// The only drawback: the user has to select again their device once the bluetooth requirements are respected.
if (error instanceof BluetoothRequired) {
setDevice(undefined);
selectDevice(undefined);
}
};

Expand Down Expand Up @@ -116,7 +112,7 @@ const WalletSyncActivationDeviceSelection: React.FC<ChooseDeviceProps> = ({
) : null}
<Flex flex={1} mb={8}>
<SelectDevice2
onSelect={onSelectDevice}
onSelect={selectDevice}
stopBleScanning={!!device || !isFocused}
requestToSetHeaderOptions={requestToSetHeaderOptions}
/>
Expand All @@ -128,6 +124,7 @@ const WalletSyncActivationDeviceSelection: React.FC<ChooseDeviceProps> = ({
action={action}
request={request}
onError={onError}
registerDeviceSelection={registerDeviceSelection}
/>
</SafeAreaView>
);
Expand Down
22 changes: 11 additions & 11 deletions apps/ledger-live-mobile/src/screens/AddAccounts/02-SelectDevice.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useCallback, useEffect, useState } from "react";
import React, { useCallback, useEffect } from "react";
import { StyleSheet, SafeAreaView } from "react-native";
import type { Device } from "@ledgerhq/live-common/hw/actions/types";
import { useIsFocused, useTheme } from "@react-navigation/native";
import { isTokenCurrency } from "@ledgerhq/live-common/currencies/index";
import { Flex } from "@ledgerhq/native-ui";
Expand All @@ -16,7 +15,7 @@ import type { AddAccountsNavigatorParamList } from "~/components/RootNavigator/t
import SkipSelectDevice from "../SkipSelectDevice";
import AddAccountsHeaderRightClose from "./AddAccountsHeaderRightClose";
import { NavigationHeaderBackButton } from "~/components/NavigationHeaderBackButton";
import { useAppDeviceAction } from "~/hooks/deviceActions";
import { useAppDeviceAction, useSelectDevice } from "~/hooks/deviceActions";

type Props = StackNavigatorProps<AddAccountsNavigatorParamList, ScreenName.AddAccountsSelectDevice>;

Expand All @@ -32,17 +31,17 @@ export default function AddAccountsSelectDevice({ navigation, route }: Props) {
const action = useAppDeviceAction();
const { currency, analyticsPropertyFlow } = route.params;
const { colors } = useTheme();
const [device, setDevice] = useState<Device | null | undefined>(null);
const { device, selectDevice, registerDeviceSelection } = useSelectDevice();
const isFocused = useIsFocused();

const onClose = useCallback(() => {
setDevice(null);
}, []);
selectDevice(null);
}, [selectDevice]);

const onResult = useCallback(
// @ts-expect-error should be AppResult but navigation.navigate does not agree
meta => {
setDevice(null);
selectDevice(null);
const { inline } = route.params;
const arg = { ...route.params, ...meta };

Expand All @@ -52,7 +51,7 @@ export default function AddAccountsSelectDevice({ navigation, route }: Props) {
navigation.navigate(ScreenName.AddAccountsAccounts, arg);
}
},
[navigation, route],
[selectDevice, navigation, route],
);

useEffect(() => {
Expand Down Expand Up @@ -89,10 +88,10 @@ export default function AddAccountsSelectDevice({ navigation, route }: Props) {
},
]}
>
<SkipSelectDevice route={route} onResult={setDevice} />
<SkipSelectDevice route={route} onResult={selectDevice} />
<Flex px={16} py={8} flex={1}>
<SelectDevice2
onSelect={setDevice}
onSelect={selectDevice}
stopBleScanning={!!device || !isFocused}
requestToSetHeaderOptions={requestToSetHeaderOptions}
/>
Expand All @@ -105,8 +104,9 @@ export default function AddAccountsSelectDevice({ navigation, route }: Props) {
request={{
currency: currency && isTokenCurrency(currency) ? currency.parentCurrency : currency,
}}
onSelectDeviceLink={() => setDevice(null)}
onSelectDeviceLink={() => selectDevice(null)}
analyticsPropertyFlow={analyticsPropertyFlow || "add account"}
registerDeviceSelection={registerDeviceSelection}
/>
</SafeAreaView>
);
Expand Down

0 comments on commit 8649ebf

Please sign in to comment.