From 8b73f6eef48aea859c3198e814b482a44c792eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Dethier?= Date: Thu, 27 Jun 2024 13:09:33 +0200 Subject: [PATCH] feat: merge protection and recovery. logion-network/logion-internal#1309 --- public/assets/lgnt.svg | 9 - public/assets/recovery-process.png | Bin 15814 -> 0 bytes src/components/coin/CoinIcon.test.tsx | 12 - src/components/coin/CoinIcon.tsx | 15 - .../coin/__snapshots__/CoinIcon.test.tsx.snap | 10 - src/wallet-user/UserDashboard.tsx | 14 - src/wallet-user/UserPaths.tsx | 2 - src/wallet-user/UserRouter.tsx | 3 - .../__snapshots__/UserDashboard.test.tsx.snap | 32 - .../__snapshots__/UserRouter.test.tsx.snap | 4 - .../protection/AccountProtectionFrame.tsx | 254 ++++ .../CreateProtectionRequestForm.test.tsx | 21 +- .../CreateProtectionRequestForm.tsx | 89 +- src/wallet-user/protection/GoToRecovery.tsx | 35 - .../protection/ProtectionRecoveryRequest.tsx | 260 +--- .../protection/TrustProtection.test.tsx | 63 + .../protection/TrustProtection.tsx | 34 +- .../CreateProtectionRequestForm.test.tsx.snap | 35 +- .../ProtectionRecoveryRequest.test.tsx.snap | 1325 +---------------- .../TrustProtection.test.tsx.snap | 20 + .../recovery/GoToTrustProtection.css | 14 - .../recovery/GoToTrustProtection.tsx | 52 - src/wallet-user/recovery/Recovery.test.tsx | 76 - src/wallet-user/recovery/Recovery.tsx | 46 - src/wallet-user/recovery/RecoveryProcess.css | 4 + src/wallet-user/recovery/RecoveryProcess.tsx | 10 +- .../recovery/VaultRecoveryProcessTab.css | 1 - .../recovery/VaultRecoveryProcessTab.tsx | 13 +- .../WalletRecoveryProcessTab.test.tsx | 2 +- .../recovery/WalletRecoveryProcessTab.tsx | 13 +- .../__snapshots__/Recovery.test.tsx.snap | 23 - 31 files changed, 485 insertions(+), 2006 deletions(-) delete mode 100644 public/assets/lgnt.svg delete mode 100644 public/assets/recovery-process.png delete mode 100644 src/components/coin/CoinIcon.test.tsx delete mode 100644 src/components/coin/CoinIcon.tsx delete mode 100644 src/components/coin/__snapshots__/CoinIcon.test.tsx.snap create mode 100644 src/wallet-user/protection/AccountProtectionFrame.tsx delete mode 100644 src/wallet-user/protection/GoToRecovery.tsx delete mode 100644 src/wallet-user/recovery/GoToTrustProtection.css delete mode 100644 src/wallet-user/recovery/GoToTrustProtection.tsx delete mode 100644 src/wallet-user/recovery/Recovery.test.tsx delete mode 100644 src/wallet-user/recovery/Recovery.tsx delete mode 100644 src/wallet-user/recovery/__snapshots__/Recovery.test.tsx.snap diff --git a/public/assets/lgnt.svg b/public/assets/lgnt.svg deleted file mode 100644 index 2f5a9bdd..00000000 --- a/public/assets/lgnt.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/public/assets/recovery-process.png b/public/assets/recovery-process.png deleted file mode 100644 index 0d81840accb6c38a3c70e2d28306a7ed3d03fecd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15814 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 Q0{{R307*qoM6N<$f-I_0p#T5? diff --git a/src/components/coin/CoinIcon.test.tsx b/src/components/coin/CoinIcon.test.tsx deleted file mode 100644 index 33be93e3..00000000 --- a/src/components/coin/CoinIcon.test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { render } from "src/tests"; -import CoinIcon from "./CoinIcon"; - -describe("CoinIcon", () => { - - it("renders LGNT", () => expectMatchSnapshot()); -}); - -function expectMatchSnapshot() { - const element = render(); - expect(element).toMatchSnapshot(); -} diff --git a/src/components/coin/CoinIcon.tsx b/src/components/coin/CoinIcon.tsx deleted file mode 100644 index fff439bc..00000000 --- a/src/components/coin/CoinIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import Icon from "src/common/Icon"; - -export interface Props { - height: string; -} - -export default function CoinIcon(props: Props) { - return ( - - ); -} diff --git a/src/components/coin/__snapshots__/CoinIcon.test.tsx.snap b/src/components/coin/__snapshots__/CoinIcon.test.tsx.snap deleted file mode 100644 index af9c718f..00000000 --- a/src/components/coin/__snapshots__/CoinIcon.test.tsx.snap +++ /dev/null @@ -1,10 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CoinIcon renders LGNT 1`] = ` -lgnt -`; diff --git a/src/wallet-user/UserDashboard.tsx b/src/wallet-user/UserDashboard.tsx index 77833f1e..5635f8aa 100644 --- a/src/wallet-user/UserDashboard.tsx +++ b/src/wallet-user/UserDashboard.tsx @@ -9,7 +9,6 @@ import { HOME_PATH, TRUST_PROTECTION_PATH, SETTINGS_PATH, - RECOVERY_PATH, locRequestsPath, ISSUER_PATH, TRANSACTIONS_PATH, @@ -167,19 +166,6 @@ export default function UserDashboard() { background: colorTheme.bottomMenuItems.iconGradient, }, }); - menuBottom.push({ - id: "recovery", - text: "Recovery", - to: RECOVERY_PATH, - exact: true, - icon: { - icon: { - id: 'recovery' - }, - background: colorTheme.recoveryItems.iconGradient, - }, - onClick: refreshAll, - }); } return ( diff --git a/src/wallet-user/UserPaths.tsx b/src/wallet-user/UserPaths.tsx index 22053248..a390c77f 100644 --- a/src/wallet-user/UserPaths.tsx +++ b/src/wallet-user/UserPaths.tsx @@ -13,8 +13,6 @@ export const TRUST_PROTECTION_RELATIVE_PATH = '/protection'; export const TRUST_PROTECTION_PATH = USER_PATH + TRUST_PROTECTION_RELATIVE_PATH; export const SETTINGS_RELATIVE_PATH = '/settings'; export const SETTINGS_PATH = USER_PATH + SETTINGS_RELATIVE_PATH; -export const RECOVERY_RELATIVE_PATH = '/recovery'; -export const RECOVERY_PATH = USER_PATH + RECOVERY_RELATIVE_PATH; export const WALLET_RELATIVE_PATH = '/wallet'; export const VAULT_RELATIVE_PATH = '/vault'; export const ISSUER_RELATIVE_PATH = '/verified-issuer'; diff --git a/src/wallet-user/UserRouter.tsx b/src/wallet-user/UserRouter.tsx index 9431c1e4..9a557023 100644 --- a/src/wallet-user/UserRouter.tsx +++ b/src/wallet-user/UserRouter.tsx @@ -8,7 +8,6 @@ import { import { TRUST_PROTECTION_RELATIVE_PATH, SETTINGS_RELATIVE_PATH, - RECOVERY_RELATIVE_PATH, TRANSACTIONS_RELATIVE_PATH, VAULT_TRANSACTIONS_RELATIVE_PATH, SETTINGS_PATH, @@ -36,7 +35,6 @@ import { useCommonContext } from "../common/CommonContext"; import { useUserContext } from "./UserContext"; import Home from "./home/Home"; import TrustProtection from "./protection/TrustProtection"; -import Recovery from "./recovery/Recovery"; import { useLogionChain } from '../logion-chain'; import IdentityLocRequest from "../loc/IdentityLocRequest"; import IssuerDashboard from "./issuer/IssuerDashboard"; @@ -63,7 +61,6 @@ export default function UserRouter() { } /> } /> - } /> - } - path="/recovery" - /> { + try { + await submitCall(activateProtection!); + } catch(e) { + console.log(e); + } finally { + clearSubmissionState(); + } + }, [ submitCall, activateProtection, clearSubmissionState ]); + + const claimRecoveryCallback = useCallback(async () => { + try { + await submitCall(claimRecovery!); + } catch(e) { + console.log(e); + } finally { + clearSubmissionState(); + } + }, [ submitCall, claimRecovery, clearSubmissionState ]); + + if(protectionState === undefined || availableLegalOfficers === undefined) { + return null; + } + + const protectionParameters = protectionState.protectionParameters; + const legalOfficer1 = protectionParameters.legalOfficers[0]; + const legalOfficer2 = protectionParameters.legalOfficers[1]; + let legalOfficer1Status: ProtectionRequestStatus; + let legalOfficer2Status: ProtectionRequestStatus; + if(protectionState instanceof PendingRecovery || protectionState instanceof RejectedRecovery) { + legalOfficer1Status = protectionParameters.states[0].status; + legalOfficer2Status = protectionParameters.states[1].status; + } else if(props.type === 'accepted') { + legalOfficer1Status = 'ACCEPTED'; + legalOfficer2Status = 'ACCEPTED'; + } else { + legalOfficer1Status = 'ACTIVATED'; + legalOfficer2Status = 'ACTIVATED'; + } + + let refusal: Refusal = 'none'; + if (props.type === 'rejected') { + refusal = protectionState.protectionParameters.states[1].status === 'REJECTED' ? 'double' : 'single'; + } + + return ( + +
+ + { + props.type === 'accepted' && !protectionParameters.isActive && !extrinsicSubmissionState.inProgress && + + + + } + { + props.type === 'activated' && protectionParameters.isRecovery && !protectionParameters.isClaimed && !extrinsicSubmissionState.inProgress && + + + + } + + + { refusal === 'double' && + + + + + + } + + + + + + { refusal === 'single' && + + } + { refusal !== 'single' && + + } + + + + + + male legal officer + female legal officer + + +

The foundation of your protection

+

+ In charge of a public office, Logion Legal Officers are identified Judicial Officers,
who apply a + strict code of ethics and are legaly responsible for their actions
+ while legally securing your digital assets and digital transactions. +

+ +
+ + ); +} + +interface HeaderProps { + type: ProtectionRecoveryRequestStatus; + protectionParameters: ProtectionParameters; +} + +function Header(props: HeaderProps) { + const forAccount = props.protectionParameters.isRecovery ? ` for account ${props.protectionParameters.recoveredAccount?.address}` : ""; + + let icon; + let color; + let text; + if(props.type === 'pending') { + if(props.protectionParameters.isRecovery) { + icon = "pending"; + color = ORANGE; + text = `Your Logion Recovery request ${forAccount} has been submitted for review. Your Legal Officers will contact you + as soon as possible to finalize the procedure.`; + } else { + icon = "pending"; + color = ORANGE; + text = `Your Logion Protection request has been submitted for review. Please note that, after the successful + completion of one of your Legal Officer approval processes, you will be able to use all features + provided by your logion account dashboard.`; + } + } else if(props.type === 'accepted') { + if(props.protectionParameters.isRecovery) { + icon = "accepted"; + color = YELLOW; + text = `Your recovery request has been accepted by your Legal Officers. + You may now activate your protection. This will require 2 signatures. + After that, you'll be able to initiate the actual recovery.`; + } else { + icon = "accepted"; + color = YELLOW; + text = `Your Logion Protection request has been accepted by your + Legal Officers. You may now activate your protection.`; + } + } else if(props.type === 'activated') { + if(props.protectionParameters.isRecovery && !props.protectionParameters.isClaimed) { + icon = "activated"; + color = GREEN; + text = `You are now ready to claim the access to address ${props.protectionParameters.recoveredAccount?.address}.`; + } else { + icon = "activated"; + color = GREEN; + text = `Your Logion Protection is active`; + } + } else if (props.type === 'rejected') { + if(props.protectionParameters.isRecovery) { + icon = "pending"; + color = ORANGE; + text=`Your Logion Recovery request has been submitted. It appears that at least one of the + selected Legal Officers refused your request: you have to decide what would be the next step. + Please note that, only after the successful completion of both of your Legal Officer approval + processes, you will be able to retrieve your assets from your previous account.`; + } else { + icon = "pending"; + color = ORANGE; + text = `Your Logion Protection request has been submitted. It appears that at least one of the + selected Legal Officers refused your request: you have to decide what would be the next step. + Please note that, only after the successful completion of your Legal Officer approval processes, + you will be able to use all features provided by your logion account dashboard.`; + } + } else { + throw new Error("Unsupported type"); + } + + const backgroundColor = rgbaToHex(color, 0.2); + return ( +
+ +
+

+ { text } +

+
+ ); +} diff --git a/src/wallet-user/protection/CreateProtectionRequestForm.test.tsx b/src/wallet-user/protection/CreateProtectionRequestForm.test.tsx index 551f27f2..1ec3a075 100644 --- a/src/wallet-user/protection/CreateProtectionRequestForm.test.tsx +++ b/src/wallet-user/protection/CreateProtectionRequestForm.test.tsx @@ -19,7 +19,7 @@ import { LocsState } from "@logion/client"; describe("CreateProtectionRequestForm", () => { it("renders", () => { - const tree = shallowRender() + const tree = shallowRender() expect(tree).toMatchSnapshot(); }); @@ -31,8 +31,7 @@ describe("CreateProtectionRequestForm", () => { it("should call submit", async () => { setLocsState(LOCS_STATE); - render(); - + render(); await selectLegalOfficers(); await clickByName("Proceed"); @@ -46,10 +45,9 @@ describe("CreateProtectionRequestForm", () => { it("should call submit for recovery and recovery already in progress", async () => { setLocsState(LOCS_STATE); - render(); - + render(); + await startRecovery(); await userEvent.type(screen.getByLabelText("Address to Recover"), TEST_WALLET_USER2.address); - await selectLegalOfficers(); await clickByName("Proceed"); @@ -64,11 +62,9 @@ describe("CreateProtectionRequestForm", () => { it("should call submit for recovery and no recovery already in progress", async () => { setLocsState(LOCS_STATE); resetSubmitting(); - - render(); - + render(); + await startRecovery(); await userEvent.type(screen.getByLabelText("Address to Recover"), TEST_WALLET_USER2.address); - await selectLegalOfficers(); await clickByName("Proceed"); @@ -81,6 +77,11 @@ describe("CreateProtectionRequestForm", () => { }); }); +async function startRecovery() { + const checkbox = screen.getByLabelText("I want to initiate a recovery"); + await userEvent.click(checkbox); +} + async function selectLegalOfficers() { const legalOfficer1Select = screen.getByTestId('legalOfficer1Group'); await userEvent.click(getByText(legalOfficer1Select, "Select...")); diff --git a/src/wallet-user/protection/CreateProtectionRequestForm.tsx b/src/wallet-user/protection/CreateProtectionRequestForm.tsx index 4332e3c3..1211fa3e 100644 --- a/src/wallet-user/protection/CreateProtectionRequestForm.tsx +++ b/src/wallet-user/protection/CreateProtectionRequestForm.tsx @@ -39,16 +39,13 @@ export function getLegalOfficerAndLocs(locsState: LocsState | undefined, client: } } -export interface Props { - isRecovery: boolean, -} - -export default function CreateProtectionRequestForm(props: Props) { +export default function CreateProtectionRequestForm() { const { api, client, clearSubmissionState, submitCall, extrinsicSubmissionState } = useLogionChain(); const { colorTheme, nodesDown } = useCommonContext(); const { createProtectionRequest, locsState, estimateFeesCreateProtectionRequest } = useUserContext(); const [ legalOfficer1, setLegalOfficer1 ] = useState(null); const [ legalOfficer2, setLegalOfficer2 ] = useState(null); + const [ isRecovery, setIsRecovery ] = useState(false); const [ addressToRecover, setAddressToRecover ] = useState(""); const [ addressToRecoverError, setAddressToRecoverError ] = useState(""); const [ fees, setFees ] = useState(); @@ -58,9 +55,9 @@ export default function CreateProtectionRequestForm(props: Props) { const canSubmit = useMemo(() => { return legalOfficer1 !== null && legalOfficer2 !== null - && (!props.isRecovery || addressToRecoverError === "") + && (!isRecovery || addressToRecoverError === "") && !legalOfficer1.legalOfficer.account.equals(legalOfficer2.legalOfficer.account); - }, [ legalOfficer1, legalOfficer2, props.isRecovery, addressToRecoverError ]); + }, [ legalOfficer1, legalOfficer2, isRecovery, addressToRecoverError ]); const createParams = useCallback<() => ProtectionRequestParams>(() => { return { @@ -68,11 +65,11 @@ export default function CreateProtectionRequestForm(props: Props) { legalOfficer1!.legalOfficer, legalOfficer2!.legalOfficer, ], - addressToRecover: props.isRecovery ? ValidAccountId.polkadot(addressToRecover) : undefined, + addressToRecover: isRecovery ? ValidAccountId.polkadot(addressToRecover) : undefined, requesterIdentityLoc1: legalOfficer1!.loc, requesterIdentityLoc2: legalOfficer2!.loc, } - }, [ legalOfficer1, legalOfficer2, addressToRecover, props.isRecovery ]); + }, [ legalOfficer1, legalOfficer2, addressToRecover, isRecovery ]); useEffect(() => { if (fees === undefined && estimateFeesCreateProtectionRequest !== null && canSubmit) { @@ -104,22 +101,15 @@ export default function CreateProtectionRequestForm(props: Props) { } }, [ createProtectionRequest, submitCall, clearSubmissionState, canSubmit, createParams ]); - let mainTitle; - if(props.isRecovery) { - mainTitle = "Recovery"; - } else { - mainTitle = "My Logion Protection"; - } - let subTitle; - if(props.isRecovery) { - subTitle = "Start recovery process"; + if(isRecovery) { + subTitle = "Initiate recovery process"; } else { subTitle = "Activate my Logion Protection"; } useEffect(() => { - if(!props.isRecovery) { + if(!isRecovery) { setAddressToRecoverError(""); } else { const account = new AnyAccountId(addressToRecover, "Polkadot"); @@ -136,25 +126,18 @@ export default function CreateProtectionRequestForm(props: Props) { setAddressToRecoverError("A valid SS58 address is required"); } } - }, [ api, addressToRecover, client, props.isRecovery ]) - - let legalOfficersTitle; - if(props.isRecovery) { - legalOfficersTitle = "Select your Legal Officers"; - } else { - legalOfficersTitle = "Choose your Legal Officers"; - } + }, [ api, addressToRecover, client, isRecovery ]) return ( { @@ -167,12 +150,34 @@ export default function CreateProtectionRequestForm(props: Props) { } - { - props.isRecovery && - -

Initiate recovery

+ +

Initiate recovery

+

+ If you already activated the protection on another account but lost + access to it, you may recover your assets my initiating a recovery. + To do so, please tick the checkbox below and follow the instructions. +

+

+ If you want to activate the protection on a new account, leave below + checkbox unticked. +

+ setIsRecovery(!isRecovery) } + /> + } + feedback={ addressToRecoverError } + colors={ colorTheme.frame } + /> + { + isRecovery && - - } + } + -

{ legalOfficersTitle }

+

Select your Legal Officers

{ - props.isRecovery && + isRecovery && Please select the 2 legal officers you’ve selected at the creation of the account to be recovered. Please note that those Legal Officers will execute their due diligence to authorize @@ -220,7 +225,7 @@ export default function CreateProtectionRequestForm(props: Props) { setLegalOfficer1={ setLegalOfficer1 } legalOfficer2={ legalOfficer2 } setLegalOfficer2={ setLegalOfficer2 } - label={ props.isRecovery ? "Select Legal Officer N°" : "Choose Legal Officer N°" } + label="Select Legal Officer N°" /> } diff --git a/src/wallet-user/protection/GoToRecovery.tsx b/src/wallet-user/protection/GoToRecovery.tsx deleted file mode 100644 index 7923319f..00000000 --- a/src/wallet-user/protection/GoToRecovery.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { useNavigate } from 'react-router'; - -import { FullWidthPane } from '../../common/Dashboard'; -import Alert from '../../common/Alert'; -import Button from '../../common/Button'; - -import { RECOVERY_PATH } from '../UserPaths'; - -export default function GoToRecovery() { - const navigate = useNavigate(); - - return ( - - - Please go to Recovery in order to follow the status of recovery process. - - - - - ); -} diff --git a/src/wallet-user/protection/ProtectionRecoveryRequest.tsx b/src/wallet-user/protection/ProtectionRecoveryRequest.tsx index bac1d6b2..0faad643 100644 --- a/src/wallet-user/protection/ProtectionRecoveryRequest.tsx +++ b/src/wallet-user/protection/ProtectionRecoveryRequest.tsx @@ -1,33 +1,20 @@ -import { useCallback } from 'react'; -import { Col, Row } from 'react-bootstrap'; -import { - UnavailableProtection, - RejectedRecovery, - PendingRecovery, -} from "@logion/client"; +import { UnavailableProtection } from "@logion/client"; import { useLogionChain } from '../../logion-chain'; import { FullWidthPane } from "../../common/Dashboard"; import Frame from "../../common/Frame"; -import Button from '../../common/Button'; import Icon from '../../common/Icon'; -import { GREEN, ORANGE, rgbaToHex, YELLOW } from '../../common/ColorTheme'; +import { GREEN } from '../../common/ColorTheme'; import { useCommonContext } from '../../common/CommonContext'; import NetworkWarning from '../../common/NetworkWarning'; import { useUserContext } from '../UserContext'; import { SETTINGS_PATH } from '../UserPaths'; -import SelectLegalOfficer from './SelectLegalOfficer'; +import AccountProtectionFrame, { ProtectionRecoveryRequestStatus } from './AccountProtectionFrame'; import './ProtectionRecoveryRequest.css'; -import { ProtectionRequestStatus } from '@logion/client'; -import RecoveryRefusal from "./RecoveryRefusal"; -import ButtonGroup from "../../common/ButtonGroup"; -import ExtrinsicSubmissionStateView from 'src/ExtrinsicSubmissionStateView'; - -export type ProtectionRecoveryRequestStatus = 'pending' | 'accepted' | 'activated' | 'unavailable' | 'rejected'; export interface Props { type: ProtectionRecoveryRequestStatus, @@ -36,29 +23,9 @@ export interface Props { export type Refusal = 'single' | 'double' | 'none'; export default function ProtectionRecoveryRequest(props: Props) { - const { getOfficer, submitCall, clearSubmissionState, extrinsicSubmissionState } = useLogionChain(); + const { getOfficer } = useLogionChain(); const { colorTheme, availableLegalOfficers, nodesDown } = useCommonContext(); - const { protectionState, activateProtection, claimRecovery } = useUserContext(); - - const activateProtectionCallback = useCallback(async () => { - try { - await submitCall(activateProtection!); - } catch(e) { - console.log(e); - } finally { - clearSubmissionState(); - } - }, [ submitCall, activateProtection, clearSubmissionState ]); - - const claimRecoveryCallback = useCallback(async () => { - try { - await submitCall(claimRecovery!); - } catch(e) { - console.log(e); - } finally { - clearSubmissionState(); - } - }, [ submitCall, claimRecovery, clearSubmissionState ]); + const { protectionState } = useUserContext(); if(protectionState === undefined || availableLegalOfficers === undefined || getOfficer === undefined) { return null; @@ -66,121 +33,22 @@ export default function ProtectionRecoveryRequest(props: Props) { if(props.type !== 'unavailable') { const protectionParameters = protectionState.protectionParameters; - const legalOfficer1 = protectionParameters.legalOfficers[0]; - const legalOfficer2 = protectionParameters.legalOfficers[1]; - let legalOfficer1Status: ProtectionRequestStatus; - let legalOfficer2Status: ProtectionRequestStatus; - if(protectionState instanceof PendingRecovery || protectionState instanceof RejectedRecovery) { - legalOfficer1Status = protectionParameters.states[0].status; - legalOfficer2Status = protectionParameters.states[1].status; - } else if(props.type === 'accepted') { - legalOfficer1Status = 'ACCEPTED'; - legalOfficer2Status = 'ACCEPTED'; - } else { - legalOfficer1Status = 'ACTIVATED'; - legalOfficer2Status = 'ACTIVATED'; - } - - const forAccount = protectionParameters.isRecovery ? ` for account ${protectionParameters.recoveredAccount?.address}` : ""; const mainTitle = protectionParameters.isRecovery && !protectionParameters.isClaimed ? "Recovery" : "My Logion Protection"; let subTitle; - let header = null; if(props.type === 'pending') { subTitle = protectionParameters.isRecovery ? "Recovery process status" : undefined; if(protectionParameters.isRecovery) { subTitle = "Recovery process status"; - header = ( -
- ); - } else { - header = ( -
- ); } } else if(props.type === 'accepted') { if(protectionParameters.isRecovery) { subTitle = "My recovery request"; - header = ( -
- ); } else { subTitle = "My Logion protection request"; - header = ( -
- ); - } - } else if(props.type === 'activated') { - if(protectionParameters.isRecovery && !protectionParameters.isClaimed) { - header = ( -
- ); - } else { - header = ( -
- ); - } - } else if (props.type === 'rejected') { - if(protectionParameters.isRecovery) { - header = ( -
- ); - } else { - header = ( -
- ); } } - let refusal: Refusal = 'none'; - if (props.type === 'rejected') { - refusal = protectionState.protectionParameters.states[1].status === 'REJECTED' ? 'double' : 'single'; - } - return ( 0 && } - - { header } - - { - props.type === 'accepted' && !protectionParameters.isActive && !extrinsicSubmissionState.inProgress && - - - - } - { - props.type === 'activated' && protectionParameters.isRecovery && !protectionParameters.isClaimed && !extrinsicSubmissionState.inProgress && - - - - } - - - { refusal === 'double' && - - - - - - } - - - - - - { refusal === 'single' && - - } - { refusal !== 'single' && - - } - - - - - - male legal officer - female legal officer - - -

The foundation of your protection

-

- In charge of a public office, Logion Legal Officers are identified Judicial Officers,
who apply a - strict code of ethics and are legaly responsible for their actions
- while legally securing your digital assets and digital transactions. -

- -
- +
); } else { @@ -327,33 +109,3 @@ export default function ProtectionRecoveryRequest(props: Props) { ); } } - -interface HeaderProps { - color: string; - icon: string; - text: string; -} - -function Header(props: HeaderProps) { - const backgroundColor = rgbaToHex(props.color, 0.2); - return ( -
- -
-

- { props.text } -

-
- ); -} diff --git a/src/wallet-user/protection/TrustProtection.test.tsx b/src/wallet-user/protection/TrustProtection.test.tsx index cfd49f31..d594ea62 100644 --- a/src/wallet-user/protection/TrustProtection.test.tsx +++ b/src/wallet-user/protection/TrustProtection.test.tsx @@ -2,12 +2,75 @@ jest.mock('../UserContext'); jest.mock('../../common/CommonContext'); jest.unmock('@logion/client'); +import { AcceptedRecovery, ActiveRecovery, ClaimedRecovery, PendingRecovery, RecoverySharedState } from "@logion/client"; +import { ValidAccountId } from "@logion/node-api"; import { setProtectionState } from "../__mocks__/UserContextMock"; import { shallowRender } from "../../tests"; import TrustProtection from "./TrustProtection"; +import { PENDING_RECOVERY_REQUESTS, ACCEPTED_RECOVERY_REQUESTS, ACTIVATED_RECOVERY_REQUESTS } from "../protection/TestData"; +import { GUILLAUME, PATRICK } from "../../common/TestData"; test("renders empty", () => { setProtectionState(undefined); const tree = shallowRender() expect(tree).toMatchSnapshot(); }); + +test("renders pending protection request", () => { + setProtectionState(new PendingRecovery({ + pendingProtectionRequests: PENDING_RECOVERY_REQUESTS, + acceptedProtectionRequests: [], + allRequests: PENDING_RECOVERY_REQUESTS, + selectedLegalOfficers: [ PATRICK, GUILLAUME ], + } as unknown as RecoverySharedState)); + + const tree = shallowRender() + + expect(tree).toMatchSnapshot(); +}); + +test("renders accepted protection request", () => { + setProtectionState(new AcceptedRecovery({ + pendingProtectionRequests: [], + acceptedProtectionRequests: ACCEPTED_RECOVERY_REQUESTS, + allRequests: ACCEPTED_RECOVERY_REQUESTS, + selectedLegalOfficers: [ PATRICK, GUILLAUME ] + } as unknown as RecoverySharedState)); + + const tree = shallowRender() + + expect(tree).toMatchSnapshot(); +}); + +test("renders protected but not claimed", () => { + setProtectionState(new ActiveRecovery({ + pendingProtectionRequests: [], + acceptedProtectionRequests: ACCEPTED_RECOVERY_REQUESTS, + allRequests: ACCEPTED_RECOVERY_REQUESTS, + selectedLegalOfficers: [ PATRICK, GUILLAUME ], + recoveryConfig: { + legalOfficers: [ PATRICK.account, GUILLAUME.account ] + } + } as unknown as RecoverySharedState)); + + const tree = shallowRender() + + expect(tree).toMatchSnapshot(); +}); + +test("renders protected and claimed", () => { + setProtectionState(new ClaimedRecovery({ + pendingProtectionRequests: [], + acceptedProtectionRequests: ACCEPTED_RECOVERY_REQUESTS, + allRequests: ACCEPTED_RECOVERY_REQUESTS, + selectedLegalOfficers: [ PATRICK, GUILLAUME ], + recoveryConfig: { + legalOfficers: [ PATRICK.account, GUILLAUME.account ] + }, + recoveredAccount: ValidAccountId.polkadot(ACTIVATED_RECOVERY_REQUESTS[0].addressToRecover!), + } as unknown as RecoverySharedState)); + + const tree = shallowRender() + + expect(tree).toMatchSnapshot(); +}); diff --git a/src/wallet-user/protection/TrustProtection.tsx b/src/wallet-user/protection/TrustProtection.tsx index 961e71ce..da448380 100644 --- a/src/wallet-user/protection/TrustProtection.tsx +++ b/src/wallet-user/protection/TrustProtection.tsx @@ -1,15 +1,18 @@ import { + AcceptedRecovery, NoProtection, + PendingRecovery, + RejectedRecovery, UnavailableProtection, } from "@logion/client"; import { useUserContext } from "../UserContext"; -import GoToRecovery from './GoToRecovery'; import CreateProtectionRequestForm from "./CreateProtectionRequestForm"; import ProtectionRecoveryRequest from './ProtectionRecoveryRequest'; import Loader from '../../common/Loader'; import { FullWidthPane } from '../../common/Dashboard'; +import RecoveryProcess from "../recovery/RecoveryProcess"; export default function TrustProtection() { const { protectionState } = useUserContext(); @@ -33,15 +36,30 @@ export default function TrustProtection() { if(protectionState instanceof UnavailableProtection) { return ; } else if(protectionState instanceof NoProtection) { - return ; + return ; } else { - const goToRecovery = protectionState.protectionParameters.isRecovery && !protectionState.protectionParameters.isClaimed; - if(goToRecovery) { - return ; - } else if(protectionState.protectionParameters.isActive) { - return ; + if(protectionState.protectionParameters.isRecovery) { + if(protectionState.protectionParameters.isActive) { + if(protectionState.protectionParameters.isClaimed) { + return ; + } else { + return ; + } + } else if(protectionState instanceof AcceptedRecovery) { + return ; + } else if(protectionState instanceof PendingRecovery) { + return ; + } else if (protectionState instanceof RejectedRecovery) { + return ; + } else { + return null; + } } else { - return null; + if(protectionState.protectionParameters.isActive) { + return ; + } else { + return null; + } } } } diff --git a/src/wallet-user/protection/__snapshots__/CreateProtectionRequestForm.test.tsx.snap b/src/wallet-user/protection/__snapshots__/CreateProtectionRequestForm.test.tsx.snap index 1b0eddf0..1539255f 100644 --- a/src/wallet-user/protection/__snapshots__/CreateProtectionRequestForm.test.tsx.snap +++ b/src/wallet-user/protection/__snapshots__/CreateProtectionRequestForm.test.tsx.snap @@ -16,12 +16,45 @@ exports[`CreateProtectionRequestForm renders 1`] = ` > + +

+ Initiate recovery +

+

+ If you already activated the protection on another account but lost access to it, you may recover your assets my initiating a recovery. To do so, please tick the checkbox below and follow the instructions. +

+

+ If you want to activate the protection on a new account, leave below checkbox unticked. +

+ + } + feedback="" + id="isRecovery" + /> +

- Choose your Legal Officers + Select your Legal Officers

- -
- - - - - - - - - - - - - - - male legal officer - female legal officer - - -

- - The foundation of - - your protection -

-

- In charge of a - - public office - - , Logion Legal Officers are - - identified Judicial Officers - - , -
- who apply a strict code of ethics and are - - legaly responsible - - for their actions -
- while legally securing your digital assets and digital transactions. -

- -
- + `; @@ -477,448 +38,9 @@ exports[`ProtectionRecoveryRequest active recovery request 1`] = ` } } > - -
- - - - - - - - - - - - - - - male legal officer - female legal officer - - -

- - The foundation of - - your protection -

-

- In charge of a - - public office - - , Logion Legal Officers are - - identified Judicial Officers - - , -
- who apply a strict code of ethics and are - - legaly responsible - - for their actions -
- while legally securing your digital assets and digital transactions. -

- -
- + `; @@ -939,437 +61,8 @@ exports[`ProtectionRecoveryRequest pending recovery request 1`] = ` } } > - -
- - - - - - - - - - - - male legal officer - female legal officer - - -

- - The foundation of - - your protection -

-

- In charge of a - - public office - - , Logion Legal Officers are - - identified Judicial Officers - - , -
- who apply a strict code of ethics and are - - legaly responsible - - for their actions -
- while legally securing your digital assets and digital transactions. -

- -
- + `; diff --git a/src/wallet-user/protection/__snapshots__/TrustProtection.test.tsx.snap b/src/wallet-user/protection/__snapshots__/TrustProtection.test.tsx.snap index 93a4e540..3495e8a1 100644 --- a/src/wallet-user/protection/__snapshots__/TrustProtection.test.tsx.snap +++ b/src/wallet-user/protection/__snapshots__/TrustProtection.test.tsx.snap @@ -1,5 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`renders accepted protection request 1`] = ` + +`; + exports[`renders empty 1`] = ` `; + +exports[`renders pending protection request 1`] = ` + +`; + +exports[`renders protected and claimed 1`] = ``; + +exports[`renders protected but not claimed 1`] = ` + +`; diff --git a/src/wallet-user/recovery/GoToTrustProtection.css b/src/wallet-user/recovery/GoToTrustProtection.css deleted file mode 100644 index 7207b491..00000000 --- a/src/wallet-user/recovery/GoToTrustProtection.css +++ /dev/null @@ -1,14 +0,0 @@ -.GoToTrustProtection .recovery-process-footer { - background: linear-gradient(to top, #e95b5b7f, #152665 50%); - position: absolute; - height: 230px; - border-radius: 9px; - bottom: 0; - right: 0; - width: 100%; - text-align: right; -} - -.GoToTrustProtection .recovery-process-footer-image { - margin-right: 30px; -} diff --git a/src/wallet-user/recovery/GoToTrustProtection.tsx b/src/wallet-user/recovery/GoToTrustProtection.tsx deleted file mode 100644 index b59d504d..00000000 --- a/src/wallet-user/recovery/GoToTrustProtection.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useNavigate } from 'react-router'; - -import { FullWidthPane } from '../../common/Dashboard'; -import Alert from '../../common/Alert'; -import Button from '../../common/Button'; -import { useCommonContext } from '../../common/CommonContext'; - -import { TRUST_PROTECTION_PATH } from '../UserPaths'; - -import './GoToTrustProtection.css'; -import Frame from '../../common/Frame'; - -export default function GoToTrustProtection() { - const { colorTheme } = useCommonContext(); - const navigate = useNavigate(); - - return ( - - - - A Trust Protection process is already in progress with this address or it is already protected. - If you want to start a recovery process, please create a new address using the extension and then - go to "Recovery". - - - -
- legal officer giving key -
- -
- ); -} diff --git a/src/wallet-user/recovery/Recovery.test.tsx b/src/wallet-user/recovery/Recovery.test.tsx deleted file mode 100644 index 691917a5..00000000 --- a/src/wallet-user/recovery/Recovery.test.tsx +++ /dev/null @@ -1,76 +0,0 @@ -jest.mock('../UserContext'); -jest.unmock("@logion/client"); - -import {shallowRender} from "../../tests"; -import Recovery from "./Recovery"; -import { setProtectionState } from '../__mocks__/UserContextMock'; -import { PENDING_RECOVERY_REQUESTS, ACCEPTED_RECOVERY_REQUESTS, ACTIVATED_RECOVERY_REQUESTS } from "../protection/TestData"; -import { PendingRecovery, ClaimedRecovery, ActiveRecovery } from "@logion/client"; -import { ValidAccountId } from "@logion/node-api"; -import { AcceptedRecovery, RecoverySharedState } from "@logion/client/dist/AccountRecovery.js"; -import { GUILLAUME, PATRICK } from "../../common/TestData"; - -test("renders", () => { - setProtectionState(undefined); - const tree = shallowRender() - expect(tree).toMatchSnapshot(); -}); - -test("renders pending protection request", () => { - setProtectionState(new PendingRecovery({ - pendingProtectionRequests: PENDING_RECOVERY_REQUESTS, - acceptedProtectionRequests: [], - allRequests: PENDING_RECOVERY_REQUESTS, - selectedLegalOfficers: [ PATRICK, GUILLAUME ], - } as unknown as RecoverySharedState)); - - const tree = shallowRender() - - expect(tree).toMatchSnapshot(); -}); - -test("renders accepted protection request", () => { - setProtectionState(new AcceptedRecovery({ - pendingProtectionRequests: [], - acceptedProtectionRequests: ACCEPTED_RECOVERY_REQUESTS, - allRequests: ACCEPTED_RECOVERY_REQUESTS, - selectedLegalOfficers: [ PATRICK, GUILLAUME ] - } as unknown as RecoverySharedState)); - - const tree = shallowRender() - - expect(tree).toMatchSnapshot(); -}); - -test("renders protected but not claimed", () => { - setProtectionState(new ActiveRecovery({ - pendingProtectionRequests: [], - acceptedProtectionRequests: ACCEPTED_RECOVERY_REQUESTS, - allRequests: ACCEPTED_RECOVERY_REQUESTS, - selectedLegalOfficers: [ PATRICK, GUILLAUME ], - recoveryConfig: { - legalOfficers: [ PATRICK.account, GUILLAUME.account ] - } - } as unknown as RecoverySharedState)); - - const tree = shallowRender() - - expect(tree).toMatchSnapshot(); -}); - -test("renders protected and claimed", () => { - setProtectionState(new ClaimedRecovery({ - pendingProtectionRequests: [], - acceptedProtectionRequests: ACCEPTED_RECOVERY_REQUESTS, - allRequests: ACCEPTED_RECOVERY_REQUESTS, - selectedLegalOfficers: [ PATRICK, GUILLAUME ], - recoveryConfig: { - legalOfficers: [ PATRICK.account, GUILLAUME.account ] - }, - recoveredAccount: ValidAccountId.polkadot(ACTIVATED_RECOVERY_REQUESTS[0].addressToRecover!), - } as unknown as RecoverySharedState)); - - const tree = shallowRender() - - expect(tree).toMatchSnapshot(); -}); diff --git a/src/wallet-user/recovery/Recovery.tsx b/src/wallet-user/recovery/Recovery.tsx deleted file mode 100644 index 260611d8..00000000 --- a/src/wallet-user/recovery/Recovery.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useUserContext } from "../UserContext"; - -import GoToTrustProtection from './GoToTrustProtection'; -import CreateProtectionRequestForm from "../protection/CreateProtectionRequestForm"; -import ProtectionRecoveryRequest from '../protection/ProtectionRecoveryRequest'; -import RecoveryProcess from './RecoveryProcess'; -import { - AcceptedRecovery, - NoProtection, - PendingRecovery, - UnavailableProtection, - RejectedRecovery -} from "@logion/client"; - -export default function Recovery() { - const { protectionState } = useUserContext(); - - if (!protectionState || protectionState.discarded) { - return null; - } - - if(protectionState instanceof UnavailableProtection) { - return ; - } else if(protectionState instanceof NoProtection) { - return ; - } else { - const goToTrustProtection = !protectionState.protectionParameters.isRecovery && !protectionState.protectionParameters.isActive; - if(goToTrustProtection) { - return ; - } else if(protectionState.protectionParameters.isActive) { - if(protectionState.protectionParameters.isClaimed) { - return ; - } else { - return ; - } - } else if(protectionState instanceof AcceptedRecovery) { - return ; - } else if(protectionState instanceof PendingRecovery) { - return ; - } else if (protectionState instanceof RejectedRecovery) { - return ; - } else { - return null; - } - } -} diff --git a/src/wallet-user/recovery/RecoveryProcess.css b/src/wallet-user/recovery/RecoveryProcess.css index 4ec587c9..bc50b033 100644 --- a/src/wallet-user/recovery/RecoveryProcess.css +++ b/src/wallet-user/recovery/RecoveryProcess.css @@ -57,3 +57,7 @@ .RecoveryProcess .asset-name-cell { line-height: 40px; } + +.RecoveryProcess .account-protection-container { + padding-top: 40px; +} diff --git a/src/wallet-user/recovery/RecoveryProcess.tsx b/src/wallet-user/recovery/RecoveryProcess.tsx index bef1f67a..b8c1b9f7 100644 --- a/src/wallet-user/recovery/RecoveryProcess.tsx +++ b/src/wallet-user/recovery/RecoveryProcess.tsx @@ -1,3 +1,4 @@ +import { Lgnt } from '@logion/node-api'; import { useState } from 'react'; import { useCommonContext } from '../../common/CommonContext'; @@ -11,9 +12,9 @@ import { useUserContext } from '../UserContext'; import WalletRecoveryProcessTab from "./WalletRecoveryProcessTab"; import VaultRecoveryProcessTab from "./VaultRecoveryProcessTab"; +import AccountProtectionFrame from '../protection/AccountProtectionFrame'; import './RecoveryProcess.css'; -import { Lgnt } from '@logion/node-api'; interface TabTitleProps { iconId: string, @@ -47,7 +48,8 @@ export default function RecoveryProcess() { return ( setTabKey(key) } /> + +
+ +
); diff --git a/src/wallet-user/recovery/VaultRecoveryProcessTab.css b/src/wallet-user/recovery/VaultRecoveryProcessTab.css index fefde7b0..21fc1859 100644 --- a/src/wallet-user/recovery/VaultRecoveryProcessTab.css +++ b/src/wallet-user/recovery/VaultRecoveryProcessTab.css @@ -4,5 +4,4 @@ .VaultRecoveryProcessTab .Table .body { overflow-y: auto; - height: calc(100vh - 575px); } diff --git a/src/wallet-user/recovery/VaultRecoveryProcessTab.tsx b/src/wallet-user/recovery/VaultRecoveryProcessTab.tsx index c742fee4..6cdd65d3 100644 --- a/src/wallet-user/recovery/VaultRecoveryProcessTab.tsx +++ b/src/wallet-user/recovery/VaultRecoveryProcessTab.tsx @@ -20,7 +20,6 @@ import { useUserContext } from "../UserContext"; import { buildOptions } from "../protection/SelectLegalOfficer"; import "./VaultRecoveryProcessTab.css" -import CoinIcon from "../../components/coin/CoinIcon"; import ExtrinsicSubmissionStateView from "../../ExtrinsicSubmissionStateView"; import AmountCell from "../../common/AmountCell"; import AssetNameCell from "../../common/AssetNameCell"; @@ -176,11 +175,6 @@ export default function VaultRecoveryProcessTab() {
, - width: "70px", - }, { header: "Name", render: coinBalance => , @@ -213,7 +207,7 @@ export default function VaultRecoveryProcessTab() { setStatus(Status.TRANSFERRING) } } > - Transfer + Recover } , @@ -235,11 +229,6 @@ export default function VaultRecoveryProcessTab() { ) } /> -
- legal officer giving key -
{ render(); let transferButton: HTMLElement; - await waitFor(() => transferButton = screen.getByRole("button", {name: "Transfer"})); + await waitFor(() => transferButton = screen.getByRole("button", {name: "Recover"})); await userEvent.click(transferButton!); let dialog: HTMLElement; diff --git a/src/wallet-user/recovery/WalletRecoveryProcessTab.tsx b/src/wallet-user/recovery/WalletRecoveryProcessTab.tsx index ccc3f445..8e05c950 100644 --- a/src/wallet-user/recovery/WalletRecoveryProcessTab.tsx +++ b/src/wallet-user/recovery/WalletRecoveryProcessTab.tsx @@ -12,7 +12,6 @@ import IconTextRow from "../../common/IconTextRow"; import { CallCallback, useLogionChain } from "../../logion-chain"; import { useUserContext } from "../UserContext"; -import CoinIcon from "../../components/coin/CoinIcon"; import ExtrinsicSubmissionStateView from "../../ExtrinsicSubmissionStateView"; import AmountCell from "../../common/AmountCell"; import { ExpectNewTransactionStatus, useCommonContext } from "../../common/CommonContext"; @@ -96,11 +95,6 @@ export default function WalletRecoveryProcessTab(props: Props) { }
, - width: "70px", - }, { header: "Name", render: coinBalance => , @@ -119,7 +113,7 @@ export default function WalletRecoveryProcessTab(props: Props) { variant="recovery" onClick={ () => setRecoveredCoinBalance(coinBalance) } > - Transfer + Recover , width: "300px", } @@ -139,11 +133,6 @@ export default function WalletRecoveryProcessTab(props: Props) { ) } /> -
- legal officer giving key -
-`; - -exports[`renders pending protection request 1`] = ` - -`; - -exports[`renders protected and claimed 1`] = ``; - -exports[`renders protected but not claimed 1`] = ` - -`;