Skip to content

Commit

Permalink
[FEAT]: Add LedgerSync status banner + hook (#7538)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcayuelas-ledger authored Aug 7, 2024
1 parent 7f588f3 commit 4dad5d0
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-hats-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"live-mobile": patch
---

Add LedgerSync status banner + hook
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from "react";
import { screen } from "@testing-library/react-native";
import { render } from "@tests/test-renderer";
import { WalletSyncSettingsNavigator } from "./shared";
import { State } from "~/reducers/types";

jest.mock("../hooks/useLedgerSyncStatus", () => ({
useLedgerSyncStatus: () => ({
error: new Error(),
isError: true,
}),
}));

describe("WalletSyncStatus", () => {
it("Should display warning banner when LedgerSync is down", async () => {
const { user } = render(<WalletSyncSettingsNavigator />, {
overrideInitialState: (state: State) => ({
...state,
settings: {
...state.settings,
readOnlyModeEnabled: false,
overriddenFeatureFlags: {
llmWalletSync: {
enabled: true,
params: {
environment: "STAGING",
watchConfig: {
pollingInterval: 10000,
initialTimeout: 5000,
userIntentDebounce: 1000,
},
},
},
},
},
trustchain: {
...state.trustchain,
trustchain: {
rootId: "rootId",
applicationPath: "applicationPath",
walletSyncEncryptionKey: "walletSyncEncryptionKey",
},
},
}),
});

// Check if the ledger sync row is visible
await expect(await screen.findByText(/ledger sync/i)).toBeVisible();

// On Press the ledger sync row
await user.press(await screen.findByText(/ledger sync/i));

// Check if the activation screen is visible
expect(await screen.findByText(/Ledger Sync is currently unavailable./i)).toBeVisible();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Alert } from "@ledgerhq/native-ui";

export function AlertLedgerSyncDown() {
const { t } = useTranslation();
return (
<Alert
type="warning"
title={t("walletSync.walletSyncActivated.errors.ledgerSyncUnavailable")}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export enum QueryKey {
getMembers = "useGetMembers",
destroyTrustchain = "useDestroyTrustchain",
fetchTrustchainStatus = "useFetchTrustchainStatus",
fetchCloudSyncStatus = "useFetchCloudSyncStatus",
}

export enum ErrorType {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useQueries, UseQueryResult } from "@tanstack/react-query";
import { QueryKey } from "./type.hooks";
import getTrustchainApi, { StatusAPIResponse as TrustchainStatus } from "@ledgerhq/trustchain/api";
import getCloudSyncApi, {
StatusAPIResponse as CloudSyncStatus,
} from "@ledgerhq/live-wallet/cloudsync/api";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";

export function useLedgerSyncStatus() {
const featureWalletSync = useFeature("llmWalletSync");
const { trustchainApiBaseUrl, cloudSyncApiBaseUrl } = getWalletSyncEnvironmentParams(
featureWalletSync?.params?.environment,
);
const QUERIES = [
{
queryKey: [QueryKey.fetchTrustchainStatus],
queryFn: () => getTrustchainApi(trustchainApiBaseUrl).fetchStatus(),
},
{
queryKey: [QueryKey.fetchCloudSyncStatus],
queryFn: () => getCloudSyncApi(cloudSyncApiBaseUrl).fetchStatus(),
},
];

return useQueries({
queries: QUERIES,
combine: combineData,
});
}

function combineData(results: UseQueryResult<TrustchainStatus | CloudSyncStatus, Error>[]) {
return {
error: results.find(result => result.isError)?.error || null,
isLoading: results.some(result => result.isLoading),
isError: results.some(result => result.isError),
};
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, Flex, Text, Icons, InfiniteLoader, Alert } from "@ledgerhq/native-ui";
import React, { useState } from "react";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Option, OptionProps } from "./Option";
import styled from "styled-components";
Expand All @@ -17,14 +17,19 @@ import ManageInstanceDrawer from "../ManageInstances/ManageInstancesDrawer";
import { useManageInstancesDrawer } from "../ManageInstances/useManageInstanceDrawer";
import ActivationDrawer from "../Activation/ActivationDrawer";
import { Steps } from "../../types/Activation";
import { TrackScreen } from "~/analytics";
import { AlertLedgerSyncDown } from "../../components/AlertLedgerSyncDown";
import { useLedgerSyncStatus } from "../../hooks/useLedgerSyncStatus";

const WalletSyncManage = () => {
const { t } = useTranslation();

const manageKeyHook = useManageKeyDrawer();
const manageInstancesHook = useManageInstancesDrawer();

const { data, isLoading, isError, error } = manageInstancesHook.memberHook;
const { error: ledgerSyncError, isError: isLedgerSyncError } = useLedgerSyncStatus();

const { data, isLoading, isError, error: manageInstancesError } = manageInstancesHook.memberHook;

const { onClickTrack } = useLedgerSyncAnalytics();

Expand Down Expand Up @@ -67,39 +72,51 @@ const WalletSyncManage = () => {
},
];

function getError(error: Error) {
// if (error instanceof UnavailableServerError) { DO SOMETHING}
const error = useMemo(
() => ledgerSyncError || manageInstancesError,
[ledgerSyncError, manageInstancesError],
);

return <Alert type="error" title={error.message} />;
}
const getTopContent = () => {
if (error) {
if (isLedgerSyncError) {
return <AlertLedgerSyncDown />;
}
return <Alert type="error" title={error.message} />;
} else {
return <Separator />;
}
};

const hasError = isLedgerSyncError || isError;

return (
<Box height="100%" paddingX="16px">
{/* <TrackPage category={AnalyticsPage.WalletSyncSettings} /> */}
<TrackScreen category={AnalyticsPage.LedgerSyncSettings} />

{isError ? getError(error) : <Separator />}
{getTopContent()}

{Options.map((props, index) => (
<Option
{...props}
key={index}
disabled={
props.id === "manageKey"
? isError && error instanceof TrustchainNotFound
? hasError && error instanceof TrustchainNotFound
? false
: isError
: isError
: hasError
: hasError
}
/>
))}

<InstancesRow disabled={isError} onPress={isError ? undefined : goToManageInstances}>
<InstancesRow disabled={hasError} onPress={isError ? undefined : goToManageInstances}>
<Container
flexDirection="row"
justifyContent="space-between"
paddingTop={24}
alignItems="center"
disabled={isError}
disabled={hasError}
>
{isLoading ? (
<InfiniteLoader size={16} />
Expand Down

0 comments on commit 4dad5d0

Please sign in to comment.