From ef99222a5adcd9732d06600bc875309c440e084f Mon Sep 17 00:00:00 2001 From: Theophile Sandoz Date: Wed, 4 Sep 2024 10:38:00 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=B9=20[FIX]:=20Handle=20Ledgersync=20o?= =?UTF-8?q?nboarding=20errors=20(#7733)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * onboarding unbacked errors for QR code and device sync * Add the `onInitialResponse` callback to `getOrCreateTrustchain` * Show the `NO_BACKUP_ONBOARDING_DEVICE` error * Show the right UnbackedError from the normal QR code flow * Show the actual unbacked errors UI * Implement `DrawerProps.retry` * Handle analytics * Update change log * Fix json formatting * Remove onboarding device error missing description --------- Co-authored-by: Theophile Sandoz --- .changeset/forty-rules-give.md | 6 +++ .../src/locales/en/common.json | 11 +++++ .../components/Activation/ActivationFlow.tsx | 30 +++++++++++++ .../features/WalletSync/hooks/useAddMember.ts | 26 ++++++----- .../hooks/useFollowInstructionDrawer.ts | 23 +++++++--- .../hooks/useLedgerSyncAnalytics.ts | 4 ++ .../WalletSync/hooks/useRemoveMember.ts | 27 +++--------- .../WalletSync/hooks/useSpecificError.tsx | 44 +++++++++++++++++++ .../screens/FollowInstructions/index.tsx | 28 ++++++++++++ libs/trustchain/src/HWDeviceProvider.ts | 4 +- libs/trustchain/src/mockSdk.ts | 20 ++++----- libs/trustchain/src/sdk.ts | 5 ++- libs/trustchain/src/types.ts | 11 +++-- 13 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 .changeset/forty-rules-give.md diff --git a/.changeset/forty-rules-give.md b/.changeset/forty-rules-give.md new file mode 100644 index 000000000000..b5ce069687e7 --- /dev/null +++ b/.changeset/forty-rules-give.md @@ -0,0 +1,6 @@ +--- +"live-mobile": minor +"@ledgerhq/trustchain": patch +--- + +Handle Ledgersync onboarding errors diff --git a/apps/ledger-live-mobile/src/locales/en/common.json b/apps/ledger-live-mobile/src/locales/en/common.json index 915c2710e410..0f27739a225d 100644 --- a/apps/ledger-live-mobile/src/locales/en/common.json +++ b/apps/ledger-live-mobile/src/locales/en/common.json @@ -6877,6 +6877,12 @@ "description": "Please make sure you’ve created an encryption key on one of your Ledger Live apps before continuing your synchronization.", "cta": "Create your encryption key" }, + "unbackedOnboarding": { + "title": "No backup detected", + "description": "Secure your other app with a Ledger then try again or continue your onboarding", + "cta": "Try again", + "cancel": "Continue without sync" + }, "backedWithDifferentSeeds": { "title": "These apps have different backups", "description": "Delete your encryption key from one of the apps and try again", @@ -6887,6 +6893,11 @@ "cta": "I understand" } }, + "unbackedOnboarding": { + "title": "This Ledger doesn’t secure a backup", + "cta": "Try another Ledger", + "cancel": "Continue without sync" + }, "alreadySecureError": { "title": "This app is already secured by this Ledger", "description": "If you are attempting to create a new backup, please connect the Ledger device you used to create your other encryption key.", diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx b/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx index e20286db7b2b..32a1ff056042 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/components/Activation/ActivationFlow.tsx @@ -1,6 +1,15 @@ +import { useNavigation } from "@react-navigation/native"; import React from "react"; +import { useSelector } from "react-redux"; import Activation from "."; import { TrackScreen } from "~/analytics"; +import { + RootNavigationComposite, + StackNavigatorNavigation, +} from "~/components/RootNavigator/types/helpers"; +import { BaseNavigatorStackParamList } from "~/components/RootNavigator/types/BaseNavigator"; +import { NavigatorName, ScreenName } from "~/const"; +import { hasCompletedOnboardingSelector } from "~/reducers/settings"; import ChooseSyncMethod from "../../screens/Synchronize/ChooseMethod"; import QrCodeMethod from "../../screens/Synchronize/QrCodeMethod"; import { Options, Steps } from "../../types/Activation"; @@ -52,6 +61,10 @@ const ActivationFlow = ({ if (input && inputCallback && nbDigits === input.length) handleSendDigits(inputCallback, input); }; + const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector); + const { navigate } = + useNavigation>>(); + const getScene = () => { switch (currentStep) { case Steps.Activation: @@ -90,6 +103,23 @@ const ActivationFlow = ({ return ; case Steps.UnbackedError: + if (!hasCompletedOnboarding) { + return ( + { + navigate(NavigatorName.BaseOnboarding, { + screen: NavigatorName.Onboarding, + params: { + screen: ScreenName.OnboardingPostWelcomeSelection, + params: { userHasDevice: true }, + }, + }); + }} + error={ErrorReason.NO_BACKUP_ONBOARDING_QRCODE} + /> + ); + } return ; case Steps.AlreadyBacked: diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useAddMember.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useAddMember.ts index c67fd7999c2b..d2f8dcd5cace 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useAddMember.ts +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useAddMember.ts @@ -6,21 +6,22 @@ import { import { useDispatch, useSelector } from "react-redux"; import { useTrustchainSdk } from "./useTrustchainSdk"; import { + NoTrustchainInitialized, TrustchainAlreadyInitialized, TrustchainAlreadyInitializedWithOtherSeed, TrustchainNotAllowed, } from "@ledgerhq/trustchain/errors"; import { TrustchainResult, TrustchainResultType } from "@ledgerhq/trustchain/types"; -import { useCallback, useEffect, useRef } from "react"; +import { useCallback, useRef } from "react"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import { useNavigation } from "@react-navigation/native"; import { WalletSyncNavigatorStackParamList } from "~/components/RootNavigator/types/WalletSyncNavigator"; import { StackNavigatorNavigation } from "~/components/RootNavigator/types/helpers"; import { ScreenName } from "~/const"; +import { hasCompletedOnboardingSelector } from "~/reducers/settings"; import { DrawerProps, SceneKind, useFollowInstructionDrawer } from "./useFollowInstructionDrawer"; export function useAddMember({ device }: { device: Device | null }): DrawerProps { - const [DrawerProps, setScene] = useFollowInstructionDrawer(); const trustchain = useSelector(trustchainSelector); const dispatch = useDispatch(); const sdk = useTrustchainSdk(); @@ -28,6 +29,7 @@ export function useAddMember({ device }: { device: Device | null }): DrawerProps const memberCredentialsRef = useRef(memberCredentials); const trustchainRef = useRef(trustchain); const navigation = useNavigation>(); + const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector); const transitionToNextScreen = useCallback( (trustchainResult: TrustchainResult) => { @@ -39,8 +41,8 @@ export function useAddMember({ device }: { device: Device | null }): DrawerProps [dispatch, navigation], ); - useEffect(() => { - const addMember = async () => { + return useFollowInstructionDrawer( + async setScene => { try { if (!device) return; if (!memberCredentialsRef.current) { @@ -50,6 +52,10 @@ export function useAddMember({ device }: { device: Device | null }): DrawerProps device.deviceId, memberCredentialsRef.current, { + onInitialResponse: trustchains => { + if (hasCompletedOnboarding || Object.keys(trustchains).length > 0) return; + else throw new NoTrustchainInitialized(); + }, onStartRequestUserInteraction: () => setScene({ kind: SceneKind.DeviceInstructions, device }), onEndRequestUserInteraction: () => setScene({ kind: SceneKind.Loader }), @@ -67,15 +73,13 @@ export function useAddMember({ device }: { device: Device | null }): DrawerProps setScene({ kind: SceneKind.AlreadySecuredSameSeed }); } else if (error instanceof TrustchainAlreadyInitializedWithOtherSeed) { setScene({ kind: SceneKind.AlreadySecuredOtherSeed }); + } else if (error instanceof NoTrustchainInitialized) { + setScene({ kind: SceneKind.UnbackedError }); } else if (error instanceof Error) { setScene({ kind: SceneKind.GenericError, error }); } } - }; - if (device && device.deviceId) { - addMember(); - } - }, [setScene, device, dispatch, sdk, transitionToNextScreen]); - - return DrawerProps; + }, + [device, sdk, transitionToNextScreen, hasCompletedOnboarding], + ); } diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useFollowInstructionDrawer.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useFollowInstructionDrawer.ts index 5332ec662466..8949b561de24 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useFollowInstructionDrawer.ts +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useFollowInstructionDrawer.ts @@ -1,5 +1,5 @@ import { useNavigation } from "@react-navigation/native"; -import { Dispatch, SetStateAction, useCallback, useState } from "react"; +import { DependencyList, useCallback, useEffect, useState } from "react"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import { StackNavigatorNavigation } from "~/components/RootNavigator/types/helpers"; import { WalletSyncNavigatorStackParamList } from "~/components/RootNavigator/types/WalletSyncNavigator"; @@ -11,6 +11,7 @@ export enum SceneKind { Loader, WrongSeedError, KeyError, + UnbackedError, GenericError, AlreadySecuredSameSeed, AlreadySecuredOtherSeed, @@ -22,24 +23,30 @@ type Scene = | { kind: SceneKind.KeyError } | { kind: SceneKind.AlreadySecuredSameSeed } | { kind: SceneKind.AlreadySecuredOtherSeed } + | { kind: SceneKind.UnbackedError } | { kind: SceneKind.GenericError; error: Error }; export type DrawerProps = { scene: Scene; - onRetry: () => void; + retry: () => void; goToDelete: () => void; backToKeyError: () => void; confirmDeleteKey: () => void; }; -export function useFollowInstructionDrawer(): [DrawerProps, Dispatch>] { +export function useFollowInstructionDrawer( + run: (setScene: (scene: Scene) => void) => Promise, + deps: DependencyList = [], +): DrawerProps { const navigation = useNavigation>(); const { deleteMutation } = useDestroyTrustchain(); const [scene, setScene] = useState({ kind: SceneKind.Loader }); - // eslint-disable-next-line no-console - const onRetry = useCallback(() => console.log("onRetry"), []); + const retry = useCallback(async () => { + setScene({ kind: SceneKind.Loader }); + await run(setScene); + }, []); // eslint-disable-line react-hooks/exhaustive-deps const goToDelete = useCallback(() => { setScene({ kind: SceneKind.WrongSeedError }); @@ -54,5 +61,9 @@ export function useFollowInstructionDrawer(): [DrawerProps, Dispatch { + run(setScene); + }, [...deps]); // eslint-disable-line react-hooks/exhaustive-deps + + return { scene, retry, goToDelete, backToKeyError, confirmDeleteKey }; } diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts index 8e2801d5f272..8c94239232bb 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts @@ -26,6 +26,8 @@ export enum AnalyticsPage { SameSeed = "App already secured with this Ledger", ScanAttemptWithSameBackup = "Scan attempt with same backup", ScanAttemptWithDifferentBackups = "Scan attempt with different backups", + OnBoardingQRCodeNoBackup = "Onboarding no backup detected", + OnBoardingDeviceNoBackup = "Onboarding this Ledger does not secure a backup", } export enum AnalyticsFlow { @@ -53,6 +55,8 @@ export enum AnalyticsButton { LedgerSync = "Ledger Sync", UseAnother = "Connect another ledger", Understand = "I understand", + TryAnotherLedger = "Try another Ledger", + ContinueWihtoutSync = "Continue without sync", } type OnClickTrack = { diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useRemoveMember.ts b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useRemoveMember.ts index 2e544ac39ef3..cca8ea995d8a 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useRemoveMember.ts +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useRemoveMember.ts @@ -7,7 +7,7 @@ import { useDispatch, useSelector } from "react-redux"; import { useTrustchainSdk } from "./useTrustchainSdk"; import { TrustchainNotAllowed } from "@ledgerhq/trustchain/errors"; import { TrustchainMember, Trustchain } from "@ledgerhq/trustchain/types"; -import { useCallback, useEffect } from "react"; +import { useCallback } from "react"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import { useNavigation } from "@react-navigation/native"; import { ScreenName } from "~/const"; @@ -21,18 +21,12 @@ type Props = { }; export function useRemoveMember({ device, member }: Props): DrawerProps { - const [DrawerProps, setScene] = useFollowInstructionDrawer(); - const dispatch = useDispatch(); const sdk = useTrustchainSdk(); const trustchain = useSelector(trustchainSelector); const memberCredentials = useSelector(memberCredentialsSelector); const navigation = useNavigation>(); - // eslint-disable-next-line no-console - const onResetFlow = useCallback(() => console.log("onResetFlow"), []); - // () => dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.SynchronizedInstances })), - const transitionToNextScreen = useCallback( (trustchainResult: Trustchain) => { if (!member) return; @@ -44,9 +38,10 @@ export function useRemoveMember({ device, member }: Props): DrawerProps { [dispatch, member, navigation], ); - const removeMember = useCallback( - async (member: TrustchainMember) => { + return useFollowInstructionDrawer( + async setScene => { try { + if (!member) return; if (!device) return; if (!trustchain || !memberCredentials) { throw new Error("trustchain or memberCredentials is not set"); @@ -72,18 +67,6 @@ export function useRemoveMember({ device, member }: Props): DrawerProps { } } }, - [setScene, device, memberCredentials, sdk, transitionToNextScreen, trustchain], + [member, device, memberCredentials, sdk, transitionToNextScreen, trustchain], ); - - useEffect(() => { - if (device && device.deviceId) { - if (!member) { - onResetFlow(); - } else { - removeMember(member); - } - } - }, [device, member, onResetFlow, removeMember]); - - return DrawerProps; } diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSpecificError.tsx b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSpecificError.tsx index 5dc711373be2..9834e3db193b 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSpecificError.tsx +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/hooks/useSpecificError.tsx @@ -14,6 +14,8 @@ export enum ErrorReason { ALREADY_BACKED_SCAN = "already-backed", DIFFERENT_BACKUPS = "different-backups", NO_BACKUP = "no-backup", + NO_BACKUP_ONBOARDING_DEVICE = "no-backup-onboarding-device", + NO_BACKUP_ONBOARDING_QRCODE = "no-backup-onboarding-qrcode", } export interface ErrorConfig { @@ -43,6 +45,11 @@ export function useSpecificError({ primaryAction, secondaryAction }: SpecificPro const onTryAgain = (page: AnalyticsPage) => { onClickTrack({ button: AnalyticsButton.UseAnother, page }); }; + + const onTryAnotherLedger = (page: AnalyticsPage) => { + onClickTrack({ button: AnalyticsButton.TryAnotherLedger, page }); + }; + const onGoToDelete = (page: AnalyticsPage) => { onClickTrack({ button: AnalyticsButton.DeleteKey, page }); }; @@ -59,6 +66,10 @@ export function useSpecificError({ primaryAction, secondaryAction }: SpecificPro onClickTrack({ button: AnalyticsButton.CreateYourKey, page }); }; + const ContinueWihtoutSync = (page: AnalyticsPage) => { + onClickTrack({ button: AnalyticsButton.ContinueWihtoutSync, page }); + }; + const errorConfig: Record = { [ErrorReason.UNSECURED]: { icon: , @@ -170,6 +181,39 @@ export function useSpecificError({ primaryAction, secondaryAction }: SpecificPro onCreate(AnalyticsPage.SyncWithNoKey); }, }, + [ErrorReason.NO_BACKUP_ONBOARDING_QRCODE]: { + icon: , + title: t("walletSync.synchronize.qrCode.unbackedOnboarding.title"), + description: t("walletSync.synchronize.qrCode.unbackedOnboarding.description"), + cta: t("walletSync.synchronize.qrCode.unbackedOnboarding.cta"), + ctaSecondary: t("walletSync.synchronize.qrCode.unbackedOnboarding.cancel"), + analyticsPage: AnalyticsPage.OnBoardingQRCodeNoBackup, + buttonType: "main" as ButtonProps["type"], + primaryAction: () => { + primaryAction(); + onTryAgain(AnalyticsPage.OnBoardingQRCodeNoBackup); + }, + secondaryAction: () => { + secondaryAction?.(); + ContinueWihtoutSync(AnalyticsPage.OnBoardingQRCodeNoBackup); + }, + }, + [ErrorReason.NO_BACKUP_ONBOARDING_DEVICE]: { + icon: , + title: t("walletSync.synchronize.unbackedOnboarding.title"), + cta: t("walletSync.synchronize.unbackedOnboarding.cta"), + ctaSecondary: t("walletSync.synchronize.unbackedOnboarding.cancel"), + analyticsPage: AnalyticsPage.OnBoardingDeviceNoBackup, + buttonType: "main" as ButtonProps["type"], + primaryAction: () => { + primaryAction(); + onTryAnotherLedger(AnalyticsPage.OnBoardingDeviceNoBackup); + }, + secondaryAction: () => { + secondaryAction?.(); + ContinueWihtoutSync(AnalyticsPage.OnBoardingDeviceNoBackup); + }, + }, }; const getErrorConfig = (error: ErrorReason) => errorConfig[error]; diff --git a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/FollowInstructions/index.tsx b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/FollowInstructions/index.tsx index 41a043e6dee5..27be1d761236 100644 --- a/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/FollowInstructions/index.tsx +++ b/apps/ledger-live-mobile/src/newArch/features/WalletSync/screens/FollowInstructions/index.tsx @@ -1,6 +1,13 @@ +import { useNavigation } from "@react-navigation/native"; import React from "react"; import QueuedDrawer from "LLM/components/QueuedDrawer"; import { TrackScreen } from "~/analytics"; +import { + RootNavigationComposite, + StackNavigatorNavigation, +} from "~/components/RootNavigator/types/helpers"; +import { BaseNavigatorStackParamList } from "~/components/RootNavigator/types/BaseNavigator"; +import { NavigatorName, ScreenName } from "~/const"; import FollowInstructions from "../../components/FollowInstructions"; import GenericErrorView from "~/components/GenericErrorView"; @@ -23,7 +30,11 @@ const GenericFollowInstructionsDrawer = ({ goToDelete, backToKeyError, confirmDeleteKey, + retry, }: Props) => { + const { navigate } = + useNavigation>>(); + const getScene = () => { switch (scene.kind) { case SceneKind.DeviceInstructions: @@ -62,6 +73,23 @@ const GenericFollowInstructionsDrawer = ({ case SceneKind.GenericError: return ; + + case SceneKind.UnbackedError: + return ( + { + navigate(NavigatorName.BaseOnboarding, { + screen: NavigatorName.Onboarding, + params: { + screen: ScreenName.OnboardingPostWelcomeSelection, + params: { userHasDevice: true }, + }, + }); + }} + /> + ); } }; diff --git a/libs/trustchain/src/HWDeviceProvider.ts b/libs/trustchain/src/HWDeviceProvider.ts index 336d21cd296c..1c5c451c9662 100644 --- a/libs/trustchain/src/HWDeviceProvider.ts +++ b/libs/trustchain/src/HWDeviceProvider.ts @@ -52,7 +52,7 @@ export class HWDeviceProvider { job: (hw: ApduDevice) => Promise, callbacks?: TrustchainDeviceCallbacks, ): Promise { - callbacks?.onStartRequestUserInteraction(); + callbacks?.onStartRequestUserInteraction?.(); const runWithDevice = this.withDevice(deviceId); try { return await lastValueFrom(runWithDevice(transport => from(job(device.apdu(transport))))); @@ -73,7 +73,7 @@ export class HWDeviceProvider { throw error; } } finally { - callbacks?.onEndRequestUserInteraction(); + callbacks?.onEndRequestUserInteraction?.(); } } diff --git a/libs/trustchain/src/mockSdk.ts b/libs/trustchain/src/mockSdk.ts index d72a4cf73de5..e7a1980685a2 100644 --- a/libs/trustchain/src/mockSdk.ts +++ b/libs/trustchain/src/mockSdk.ts @@ -107,18 +107,18 @@ export class MockSDK implements TrustchainSDK { trustchains.set(trustchain.rootId, trustchain); if (!this.deviceJwtAcquired) { - callbacks?.onStartRequestUserInteraction(); + callbacks?.onStartRequestUserInteraction?.(); this.deviceJwtAcquired = true; // simulate device auth interaction - callbacks?.onEndRequestUserInteraction(); + callbacks?.onEndRequestUserInteraction?.(); } const currentMembers = trustchainMembers.get(trustchain.rootId) || []; // add itself if not yet here if (!currentMembers.some(m => m.id === memberCredentials.pubkey)) { if (type === TrustchainResultType.restored) type = TrustchainResultType.updated; - callbacks?.onStartRequestUserInteraction(); + callbacks?.onStartRequestUserInteraction?.(); // simulate device add interaction - callbacks?.onEndRequestUserInteraction(); + callbacks?.onEndRequestUserInteraction?.(); currentMembers.push({ id: memberCredentials.pubkey, name: this.context.name, @@ -179,18 +179,18 @@ export class MockSDK implements TrustchainSDK { ); if (!this.deviceJwtAcquired) { - callbacks?.onStartRequestUserInteraction(); + callbacks?.onStartRequestUserInteraction?.(); this.deviceJwtAcquired = true; // simulate device auth interaction - callbacks?.onEndRequestUserInteraction(); + callbacks?.onEndRequestUserInteraction?.(); } - callbacks?.onStartRequestUserInteraction(); + callbacks?.onStartRequestUserInteraction?.(); // simulate device interaction - callbacks?.onEndRequestUserInteraction(); + callbacks?.onEndRequestUserInteraction?.(); - callbacks?.onStartRequestUserInteraction(); + callbacks?.onStartRequestUserInteraction?.(); // simulate device interaction - callbacks?.onEndRequestUserInteraction(); + callbacks?.onEndRequestUserInteraction?.(); const currentMembers = (trustchainMembers.get(trustchain.rootId) || []).filter( m => m.id !== member.id, diff --git a/libs/trustchain/src/sdk.ts b/libs/trustchain/src/sdk.ts index cb82274bb993..1ec3fab08512 100644 --- a/libs/trustchain/src/sdk.ts +++ b/libs/trustchain/src/sdk.ts @@ -10,6 +10,7 @@ import { TrustchainResult, TrustchainResultType, TrustchainLifecycle, + GetOrCreateTrustchainCallbacks, } from "./types"; import { crypto, @@ -101,7 +102,7 @@ export class SDK implements TrustchainSDK { async getOrCreateTrustchain( deviceId: string, memberCredentials: MemberCredentials, - callbacks?: TrustchainDeviceCallbacks, + callbacks?: GetOrCreateTrustchainCallbacks, topic?: Uint8Array, currentTrustchainId?: string, ): Promise { @@ -115,6 +116,8 @@ export class SDK implements TrustchainSDK { let trustchains = await withJwt(this.api.getTrustchains); + callbacks?.onInitialResponse?.(trustchains); + if (currentTrustchainId) { if ( Object.keys(trustchains).length > 0 && diff --git a/libs/trustchain/src/types.ts b/libs/trustchain/src/types.ts index 46f17f6b44ce..573300cc68ec 100644 --- a/libs/trustchain/src/types.ts +++ b/libs/trustchain/src/types.ts @@ -1,5 +1,6 @@ import { Observable } from "rxjs"; import Transport from "@ledgerhq/hw-transport"; +import { TrustchainsResponse } from "./api"; /** * The JWT is a JSON Web Token that is used to authenticate the user. @@ -172,7 +173,7 @@ export interface TrustchainSDK { getOrCreateTrustchain( deviceId: string, memberCredentials: MemberCredentials, - callbacks?: TrustchainDeviceCallbacks, + callbacks?: GetOrCreateTrustchainCallbacks, topic?: Uint8Array, currentTrustchainId?: string, ): Promise; @@ -232,6 +233,10 @@ export interface TrustchainSDK { } export interface TrustchainDeviceCallbacks { - onStartRequestUserInteraction: () => void; - onEndRequestUserInteraction: () => void; + onStartRequestUserInteraction?: () => void; + onEndRequestUserInteraction?: () => void; +} + +export interface GetOrCreateTrustchainCallbacks extends TrustchainDeviceCallbacks { + onInitialResponse?: (trustchains: TrustchainsResponse) => void; }