diff --git a/.changeset/curly-tables-chew.md b/.changeset/curly-tables-chew.md new file mode 100644 index 000000000000..f848b8222cb8 --- /dev/null +++ b/.changeset/curly-tables-chew.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +fix(RecoverRestore): add onRetry to error handling diff --git a/apps/ledger-live-desktop/src/renderer/components/RecoverRestore/index.tsx b/apps/ledger-live-desktop/src/renderer/components/RecoverRestore/index.tsx index c4b2892c3ff0..4bccf53bc86c 100644 --- a/apps/ledger-live-desktop/src/renderer/components/RecoverRestore/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/RecoverRestore/index.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from "react"; +import React, { useCallback, useContext, useEffect, useRef, useState } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import { useHistory } from "react-router-dom"; @@ -13,7 +13,7 @@ import { ScreenId } from "../Onboarding/Screens/Tutorial"; import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess"; import getVersion from "@ledgerhq/live-common/hw/getVersion"; import { first } from "rxjs/operators"; -import { from } from "rxjs"; +import { Subscription, from } from "rxjs"; import { OnboardingState, extractOnboardingState, @@ -31,34 +31,48 @@ const RecoverRestore = () => { const [error, setError] = useState(); const { setDeviceModelId } = useContext(OnboardingContext); const locale = useSelector(languageSelector) || "en"; + const sub = useRef(); + + const getOnboardingState = useCallback((device: Device) => { + sub.current?.unsubscribe(); + + const requestObservable = withDevice(device.deviceId)(t => from(getVersion(t))).pipe(first()); + + sub.current = requestObservable.subscribe({ + next: (firmware: FirmwareInfo) => { + try { + setState(extractOnboardingState(firmware.flags)); + } catch (error: unknown) { + if (error instanceof Error) { + setError(error); + } + } + }, + error: (error: Error) => { + setError(error); + }, + }); + }, []); // check if device is seeded when selected useEffect(() => { if (currentDevice) { - const requestObservable = withDevice(currentDevice.deviceId)(t => from(getVersion(t))).pipe( - first(), - ); - - const sub = requestObservable.subscribe({ - next: (firmware: FirmwareInfo) => { - try { - setState(extractOnboardingState(firmware.flags)); - } catch (error: unknown) { - if (error instanceof Error) { - setError(error); - } - } - }, - error: (error: Error) => { - setError(error); - }, - }); + getOnboardingState(currentDevice); return () => { - sub.unsubscribe(); + sub.current?.unsubscribe(); + sub.current = undefined; }; } - }, [currentDevice]); + }, [currentDevice, getOnboardingState]); + + // cleanup subscription in case of retry and component unmount + useEffect(() => { + return () => { + sub.current?.unsubscribe(); + sub.current = undefined; + }; + }, []); useEffect(() => { if (state && !state.isOnboarded) { @@ -76,11 +90,18 @@ const RecoverRestore = () => { } }, [currentDevice?.modelId, history, setDeviceModelId, state]); + const onRetry = useCallback(() => { + setState(undefined); + setError(undefined); + if (currentDevice) getOnboardingState(currentDevice); + }, [currentDevice, getOnboardingState]); + if (error) { return renderError({ t, error, device: currentDevice, + onRetry, }); }