Skip to content

Commit

Permalink
Merge pull request #7038 from LedgerHQ/feat/manage-instances-LLD
Browse files Browse the repository at this point in the history
[FEAT]  : Manage instances in LLD
  • Loading branch information
cgrellard-ledger committed Jun 11, 2024
2 parents 04ae377 + fded14f commit 0e5b042
Show file tree
Hide file tree
Showing 25 changed files with 615 additions and 96 deletions.
5 changes: 5 additions & 0 deletions .changeset/plenty-elephants-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": patch
---

Add manage Synchronized instances in Debugger + WalletSync
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import DeviceActionStep from "./02-DeviceActionStep";
import ActivationOrSynchroWithTrustchain from "./03-ActivationOrSynchroWithTrustchain";
import ActivationFinalStep from "./04-ActivationFinalStep";
import { useBackup } from "../ManageBackup/useBackup";
import { useInstances } from "../ManageInstances/useInstances";

const WalletSyncActivation = () => {
const dispatch = useDispatch();
const { hasBackup, createBackup } = useBackup();
const { createInstance } = useInstances();

const { currentStep, goToNextScene } = useFlows({ flow: Flow.Activation });

Expand All @@ -24,6 +26,11 @@ const WalletSyncActivation = () => {
const createNewBackupAction = () => {
goToNextScene();
createBackup();
createInstance({
name: "Iphone 8",
id: "1",
typeOfDevice: "mobile",
});
};

const getStep = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import useTheme from "~/renderer/hooks/useTheme";
import { useDispatch } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
import { OptionContainer, Option, OptionProps } from "./Option";
import { Option, OptionProps } from "./Option";
import styled from "styled-components";
import { useInstances } from "../ManageInstances/useInstances";

const Separator = () => {
const { colors } = useTheme();
Expand All @@ -14,7 +16,7 @@ const Separator = () => {

const WalletSyncManage = () => {
const { t } = useTranslation();
const nbInstances = 1;
const { instances } = useInstances();

const dispatch = useDispatch();

Expand All @@ -26,6 +28,10 @@ const WalletSyncManage = () => {
dispatch(setFlow({ flow: Flow.ManageBackups, step: Step.ManageBackup }));
};

const goToManageInstances = () => {
dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.SynchronizedInstances }));
};

const Options: OptionProps[] = [
{
label: t("walletSync.manage.synchronize.label"),
Expand Down Expand Up @@ -55,20 +61,29 @@ const WalletSyncManage = () => {
<Option {...props} key={index} />
))}

<Flex paddingY={24} justifyContent="space-between">
<InstancesRow
paddingY={24}
justifyContent="space-between"
onClick={goToManageInstances}
data-testid="walletSync-manage-instances"
>
<Text fontSize={13.44}>
{t("walletSync.manage.instance.label", { count: nbInstances })}
{t("walletSync.manage.instance.label", { count: instances.length })}
</Text>

<OptionContainer>
<Flex columnGap={"8px"} alignItems={"center"}>
<Text fontSize={13.44}>{t("walletSync.manage.instance.cta")}</Text>
<Icons.ChevronRight size="S" />
</Flex>
</OptionContainer>
</Flex>
<Flex columnGap={"8px"} alignItems={"center"}>
<Text fontSize={13.44}>{t("walletSync.manage.instance.cta")}</Text>
<Icons.ChevronRight size="S" />
</Flex>
</InstancesRow>
</Box>
);
};

export default WalletSyncManage;

const InstancesRow = styled(Flex)`
&:hover {
cursor: pointer;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import BackupDeleted from "./03-FinalStep";
import { useBackup } from "./useBackup";

const WalletSyncManageBackups = forwardRef<BackRef, BackProps>((_props, ref) => {
const { currentStep, goToNextScene, goToPreviousScene, FlowOptions, resetFlows } = useFlows({
const {
currentStep,
goToNextScene,
goToPreviousScene,
FlowOptions,
goToWelcomeScreenWalletSync,
} = useFlows({
flow: Flow.ManageBackups,
});

Expand All @@ -24,7 +30,7 @@ const WalletSyncManageBackups = forwardRef<BackRef, BackProps>((_props, ref) =>

const goBack = () => {
if (currentStep === FlowOptions[Flow.ManageBackups].steps[1]) {
resetFlows();
goToWelcomeScreenWalletSync();
} else {
goToPreviousScene();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Flex, Text } from "@ledgerhq/react-ui";
import React from "react";
import { useTranslation } from "react-i18next";
import { AnalyticsPage, useWalletSyncAnalytics } from "../../useWalletSyncAnalytics";
import TrackPage from "~/renderer/analytics/TrackPage";
import { TinyCard } from "../../components/TinyCard";
import { Instance } from "~/renderer/reducers/walletSync";

type Props = {
instances: Instance[];
goToDeleteInstance: (instance: Instance) => void;
};

export default function ManageInstancesStep({ goToDeleteInstance, instances }: Props) {
const { t } = useTranslation();

const { onClickTrack } = useWalletSyncAnalytics();

const handleGoDeleteInstance = (instance: Instance) => {
onClickTrack({ button: "remove instance", page: AnalyticsPage.ManageInstances });
goToDeleteInstance(instance);
};

return (
<Flex flexDirection="column" rowGap="24px" paddingX="40px">
<TrackPage category={AnalyticsPage.ManageInstances} />
<Text fontSize={23} variant="large" color="neutral.c100">
{t("walletSync.manageInstances.title")}
</Text>

{instances.map(instance => (
<TinyCard
key={instance.id}
testId={`walletSync-manage-instance-${instance.id}`}
text={instance.name}
cta={t("walletSync.manageInstances.remove")}
onClick={() => handleGoDeleteInstance(instance)}
/>
))}
</Flex>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { getEnv } from "@ledgerhq/live-env";
import React, { useMemo } from "react";
import DeviceAction from "~/renderer/components/DeviceAction";
import { mockedEventEmitter } from "~/renderer/components/debug/DebugMock";
import connectApp from "@ledgerhq/live-common/hw/connectApp";
import { createAction } from "@ledgerhq/live-common/hw/actions/app";
import { getCryptoCurrencyById } from "@ledgerhq/live-common/currencies/index";

const action = createAction(getEnv("MOCK") ? mockedEventEmitter : connectApp);

type Props = {
goNext: () => void;
};

export default function DeviceActionInstanceStep({ goNext }: Props) {
//const request = { appName: "BOLOS" };
const currency = getCryptoCurrencyById("bitcoin");
const request = useMemo(() => ({ currency }), [currency]);

//IF ERROR Device
// dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.InstanceErrorDeletion }));

return <DeviceAction action={action} request={request} onResult={() => goNext()} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useCallback, useEffect } from "react";
import Loading from "../../components/LoadingStep";
import { useTranslation } from "react-i18next";
import { Flow, Instance, Step } from "~/renderer/reducers/walletSync";
import { useInstances } from "./useInstances";
import { useDispatch } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";

type Props = {
instance: Instance | null;
};

export default function DeleteInstanceWithTrustchain({ instance }: Props) {
const { t } = useTranslation();
const dispatch = useDispatch();
const { deleteInstance } = useInstances();

// TO CHANGE WHEN INTRAGRATION WITH TRUSTCHAIN
const stuffHandledByTrustchain = useCallback(() => {
dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.InstanceSuccesfullyDeleted }));
deleteInstance(instance as Instance);

//IF ERROR
// dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.InstanceErrorDeletion }));
}, [deleteInstance, dispatch, instance]);

// TO CHANGE WHEN INTRAGRATION WITH TRUSTCHAIN
useEffect(() => {
setTimeout(() => {
stuffHandledByTrustchain();
}, 3000);
}, [stuffHandledByTrustchain]);

return <Loading title={t("walletSync.loading.title")} subtitle={t("walletSync.loading.synch")} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import { Error } from "../../components/Error";
import { useTranslation } from "react-i18next";
import { Instance } from "~/renderer/reducers/walletSync";
import { Flex } from "@ledgerhq/react-ui";

type Props = {
instance: Instance | null;
};

export default function DeletionErrorFinalStep({ instance }: Props) {
const { t } = useTranslation();
const title = "walletSync.manageInstances.deleteInstanceError";
return (
<Flex flexDirection="column" alignItems="center" justifyContent="center" height="100%">
<Error
title={t(title, {
instanceName: instance?.name,
})}
/>
</Flex>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import { Success } from "../../components/Success";
import { useTranslation } from "react-i18next";
import { Instance } from "~/renderer/reducers/walletSync";
import { Flex } from "@ledgerhq/react-ui";

type Props = {
instance: Instance | null;
};

export default function DeletionFinalStep({ instance }: Props) {
const { t } = useTranslation();
const title = "walletSync.manageInstances.deleteInstanceSuccess";
return (
<Flex flexDirection="column" alignItems="center" justifyContent="center" height="100%">
<Success
title={t(title, {
instanceName: instance?.name,
})}
/>
</Flex>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React, { forwardRef, useImperativeHandle } from "react";
import { Flex } from "@ledgerhq/react-ui";
import { Flow, Instance, Step } from "~/renderer/reducers/walletSync";
import { useFlows } from "LLD/WalletSync/Flows/useFlows";
import { BackProps, BackRef } from "../router";
import ManageInstancesStep from "./01-ManageInstancesStep";
import DeviceActionInstanceStep from "./02-DeviceActionInstanceStep";
import { useInstances } from "./useInstances";
import DeleteInstanceWithTrustchain from "./03-DeleteInstanceWithTrustchain";
import DeletionFinalStep from "./04-DeletionFinalStep";
import DeletionErrorFinalStep from "./04-DeletionFinalErrorStep";
import { UnsecuredError } from "../Activation/03-UnsecuredError";

const WalletSyncManageInstances = forwardRef<BackRef, BackProps>((_props, ref) => {
const {
currentStep,
goToNextScene,
goToPreviousScene,
FlowOptions,
goToWelcomeScreenWalletSync,
} = useFlows({
flow: Flow.ManageInstances,
});

const { instances, selectedInstance, setSelectedInstance } = useInstances();

useImperativeHandle(ref, () => ({
goBack,
}));

const goBack = () => {
if (currentStep === FlowOptions[Flow.ManageInstances].steps[1]) {
goToWelcomeScreenWalletSync();
} else {
goToPreviousScene();
}
};

const goToDeleteInstance = (instance: Instance) => {
setSelectedInstance(instance);
goToNextScene();
};

const getStep = () => {
switch (currentStep) {
default:
case Step.SynchronizedInstances:
return (
<ManageInstancesStep goToDeleteInstance={goToDeleteInstance} instances={instances} />
);
case Step.DeviceActionInstance:
return <DeviceActionInstanceStep goNext={goToNextScene} />;
case Step.DeleteInstanceWithTrustChain:
return <DeleteInstanceWithTrustchain instance={selectedInstance} />;
case Step.InstanceSuccesfullyDeleted:
return <DeletionFinalStep instance={selectedInstance} />;
case Step.InstanceErrorDeletion:
return <DeletionErrorFinalStep instance={selectedInstance} />;
case Step.UnsecuredLedger:
return <UnsecuredError />;
}
};

return (
<Flex flexDirection="column" height="100%" rowGap="48px">
{getStep()}
</Flex>
);
});

WalletSyncManageInstances.displayName = "WalletSyncManageInstances";
export default WalletSyncManageInstances;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addInstance, removeAllInstances, removeInstance } from "~/renderer/actions/walletSync";
import { Instance, walletSyncInstancesSelector } from "~/renderer/reducers/walletSync";

export const useInstances = () => {
const [selectedInstance, setSelectedInstance] = useState<Instance | null>(null);
const dispatch = useDispatch();
const instances = useSelector(walletSyncInstancesSelector);

const deleteInstance = (instance: Instance) => dispatch(removeInstance(instance));

const createInstance = (instance: Instance) => dispatch(addInstance(instance));

const deleteAllInstances = () => dispatch(removeAllInstances);

return {
instances,
deleteInstance,
deleteAllInstances,
createInstance,
selectedInstance,
setSelectedInstance,
};
};
Loading

0 comments on commit 0e5b042

Please sign in to comment.