From 353cfe80568f6667334d8c5d27c09fac248f03ca Mon Sep 17 00:00:00 2001 From: "przemyslaw.wlodek" Date: Tue, 28 Nov 2023 11:02:39 +0100 Subject: [PATCH 1/9] feat(extension): add drep retirement id mismatch modal --- .../ConfirmDRepRetirementContainer.tsx | 13 ++-- ...mDRepRetirementIdMismatchModal.module.scss | 50 ++++++++++++++ .../ConfirmDRepRetirementIdMismatchModal.tsx | 50 ++++++++++++++ .../ConfirmTransaction.module.scss | 23 ------- .../ConfirmTransaction.tsx | 41 +---------- .../ConfirmDRepRetirementFooter.tsx | 69 +++++++++++++++++++ .../ConfirmTransactionFooter.tsx | 23 +++++++ ...ConfirmTransactionFooterCommon.module.scss | 15 ++++ .../ConfirmTransactionFooterCommon.tsx | 47 +++++++++++++ .../ConfirmTransactionFooter/index.ts | 1 + .../__tests__/hooks.test.tsx | 2 +- .../__tests__/utils.test.tsx | 7 -- .../components/confirm-transaction/hooks.ts | 24 ++++--- .../components/confirm-transaction/utils.ts | 7 -- .../src/lib/translations/en.json | 10 ++- 15 files changed, 286 insertions(+), 96 deletions(-) create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.module.scss create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.tsx create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx index 42650c2b8e..ee46621957 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx @@ -1,11 +1,10 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { ConfirmDRepRetirement } from '@lace/core'; -import { SignTxData } from './types'; -import { certificateInspectorFactory, drepIDasBech32FromHash, getOwnRetirementMessageKey } from './utils'; +import { certificateInspectorFactory, drepIDasBech32FromHash } from './utils'; import { Wallet } from '@lace/cardano'; import { useWalletStore } from '@src/stores'; -import { useIsOwnPubDRepKey } from './hooks'; +import { SignTxData } from './types'; const { CertificateType } = Wallet.Cardano; @@ -17,8 +16,7 @@ interface Props { export const ConfirmDRepRetirementContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { const { t } = useTranslation(); const { - walletUI: { cardanoCoin }, - inMemoryWallet + walletUI: { cardanoCoin } } = useWalletStore(); const certificate = certificateInspectorFactory( CertificateType.UnregisterDelegateRepresentative @@ -27,9 +25,6 @@ export const ConfirmDRepRetirementContainer = ({ signTxData, errorMessage }: Pro cardanoCoin.symbol }`; - const isOwnRetirement = useIsOwnPubDRepKey(inMemoryWallet.getPubDRepKey, certificate.dRepCredential.hash); - const ownRetirementMessageKey = getOwnRetirementMessageKey(isOwnRetirement); - return ( ); }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.module.scss new file mode 100644 index 0000000000..f4b404cb86 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.module.scss @@ -0,0 +1,50 @@ +@import '../../../../../../../packages/common/src/ui/styles/theme.scss'; + +.modal { + :global(.ant-modal-content) { + background: var(--color-white, var(--dark-mode-light-black)); + box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.05), 0px 0px 40px rgba(0, 0, 0, 0.05); + border-radius: size_unit(4); + } + :global(.ant-modal-body) { + display: flex; + flex-direction: column; + padding: size_unit(5) !important; + } +} + +.header { + color: var(--text-color-primary); + font-size: var(--subHeading); + font-weight: bold; + line-height: size_unit(4); + text-align: center; +} + +.content { + align-items: center; + color: var(--text-color-secondary); + display: flex; + flex: 1; + flex-direction: column; + font-size: var(--body); + font-weight: normal; + justify-content: center; + line-height: size_unit(3); + text-align: center; + padding: 0 size_unit(2); + margin-top: size_unit(3); + margin-bottom: size_unit(4); +} + +.label { + color: $theme-text-color-black; + margin-top: size_unit(2); + font-weight: bold; +} + +.footer { + display: flex; + flex-direction: column; + gap: size_unit(2); +} diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.tsx new file mode 100644 index 0000000000..7885f273a4 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal.tsx @@ -0,0 +1,50 @@ +/* eslint-disable unicorn/no-null */ +import React from 'react'; +import { Modal } from 'antd'; +import { Button, Ellipsis } from '@lace/common'; +import { useTranslation } from 'react-i18next'; +import styles from './ConfirmDRepRetirementIdMismatchModal.module.scss'; + +// TODO: add a JIRA ticket to unify modals in one reusable component +// right now we have this component repeated in several places https://input-output.atlassian.net/browse/LW-5295 +const modalPopupWidth = 312; + +export type ConfirmDRepRetirementIdMismatchDialogProps = { + open: boolean; + expectedDRepId: string; + givenDRepId: string; + onCancel: () => void; + onConfirm: () => void; +}; + +export const ConfirmDRepRetirementIdMismatchModal = ({ + open, + expectedDRepId = 'abc', + givenDRepId = 'cba', + onCancel, + onConfirm +}: ConfirmDRepRetirementIdMismatchDialogProps): React.ReactElement => { + const { t } = useTranslation(); + return ( + +
+ {t('core.DRepRetirement.drepIdMismatchModal.title')} +
+
+ {t('core.DRepRetirement.drepIdMismatchModal.description')} + {t('core.DRepRetirement.drepIdMismatchModal.givenDRepId')} + + {t('core.DRepRetirement.drepIdMismatchModal.expectedDRepId')} + +
+
+ + +
+
+ ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss index 9d25c19f3c..6f5d3c5f26 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss @@ -1,30 +1,7 @@ @import '../../../../../../../packages/common/src/ui/styles/theme.scss'; @import '../../../../../src/styles/rules/flex.scss'; -.actions { - display: flex; - gap: size_unit(1); - justify-content: space-evenly; - flex-direction: column; -} - .spaceBetween { justify-content: space-between; padding-top: size_unit(2); } - -.actions { - background-color: var(--bg-color-body); - @extend %flex-column; - justify-content: center; - gap: size_unit(1); - padding: size_unit(2) size_unit(3) size_unit(2) size_unit(3); - border-top: 2px solid var(--light-mode-light-grey-plus, var(--dark-mode-mid-grey)); - margin: size_unit(4) size_unit(-3) size_unit(-2) size_unit(-3); - position: sticky; - bottom: 0; - .actionBtn { - width: 100%; - } - z-index: 10; -} diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx index ba6ea45711..d4000f4780 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx @@ -1,25 +1,19 @@ /* eslint-disable no-console */ import React, { useMemo } from 'react'; -import { Button } from '@lace/common'; import { useTranslation } from 'react-i18next'; import { Layout } from '../Layout'; -import { useViewsFlowContext } from '@providers/ViewFlowProvider'; import styles from './ConfirmTransaction.module.scss'; -import { Wallet } from '@lace/cardano'; -import { useWalletStore } from '@stores'; -import { useDisallowSignTx, useSignWithHardwareWallet, useSignTxData, useOnBeforeUnload } from './hooks'; +import { useSignTxData } from './hooks'; import { consumeRemoteApi, RemoteApiPropertyType } from '@cardano-sdk/web-extension'; import { DappDataService } from '@lib/scripts/types'; import { DAPP_CHANNELS } from '@src/utils/constants'; import { runtime } from 'webextension-polyfill'; import { getTitleKey, getTxType } from './utils'; import { ConfirmTransactionContent } from './ConfirmTransactionContent'; +import { ConfirmTransactionFooter } from './ConfirmTransactionFooter'; export const ConfirmTransaction = (): React.ReactElement => { const { t } = useTranslation(); - const { - utils: { setNextView } - } = useViewsFlowContext(); const dappDataApi = useMemo( () => consumeRemoteApi>( @@ -33,43 +27,14 @@ export const ConfirmTransaction = (): React.ReactElement => { ), [] ); - const { getKeyAgentType } = useWalletStore(); const { signTxData, errorMessage } = useSignTxData(dappDataApi.getSignTxData); - const keyAgentType = getKeyAgentType(); - const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; - const disallowSignTx = useDisallowSignTx(); - const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); const txType = signTxData ? getTxType(signTxData.tx) : undefined; const title = txType ? t(getTitleKey(txType)) : ''; - useOnBeforeUnload(disallowSignTx); - return ( -
- - -
+
); }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx new file mode 100644 index 0000000000..571ec018a8 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx @@ -0,0 +1,69 @@ +import React, { useCallback, useState } from 'react'; +import { Button } from '@lace/common'; +import { Wallet } from '@lace/cardano'; +import { useViewsFlowContext } from '@providers/ViewFlowProvider'; +import { useWalletStore } from '@stores'; +import { useDisallowSignTx, useGetOwnPubDRepKeyHash, useOnBeforeUnload, useSignWithHardwareWallet } from '../hooks'; +import { certificateInspectorFactory } from '../utils'; +import { SignTxData } from '../types'; +import styles from './ConfirmTransactionFooterCommon.module.scss'; +import { useTranslation } from 'react-i18next'; +import { ConfirmDRepRetirementIdMismatchModal } from '@src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal'; + +type ConfirmTransactionFooterProps = { + signTxData?: SignTxData; + errorMessage?: string; +}; + +export const ConfirmDRepRetirementFooter = ({ + signTxData, + errorMessage +}: ConfirmTransactionFooterProps): React.ReactElement => { + const { t } = useTranslation(); + const disallowSignTx = useDisallowSignTx(); + const { + utils: { setNextView } + } = useViewsFlowContext(); + const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); + const keyAgentType = useWalletStore((store) => store.getKeyAgentType()); + const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; + const [dRepIdMismatchModalOpen, setDRepIdMismatchModalOpen] = useState(false); + const handleSubmit = useCallback(async () => { + isUsingHardwareWallet ? await signWithHardwareWallet() : setNextView(); + }, [isUsingHardwareWallet, setNextView, signWithHardwareWallet]); + const { + dRepCredential: { hash: transactionDrepKeyHash } + } = certificateInspectorFactory( + Wallet.Cardano.CertificateType.UnregisterDelegateRepresentative + )(signTxData.tx); + const { loading, ownPubDRepKeyHash } = useGetOwnPubDRepKeyHash(); + const isOwnDRepKey = transactionDrepKeyHash === ownPubDRepKeyHash; + + useOnBeforeUnload(disallowSignTx); + + return ( +
+ setDRepIdMismatchModalOpen(false)} + /> + + +
+ ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx new file mode 100644 index 0000000000..208f7beecc --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { TxType } from '../utils'; +import { SignTxData } from '../types'; +import { ConfirmTransactionFooterCommon } from './ConfirmTransactionFooterCommon'; +import { ConfirmDRepRetirementFooter } from './ConfirmDRepRetirementFooter'; + +type ConfirmTransactionFooterProps = { + txType?: TxType; + signTxData?: SignTxData; + errorMessage?: string; +}; + +export const ConfirmTransactionFooter = ({ + txType, + signTxData, + errorMessage +}: ConfirmTransactionFooterProps): React.ReactElement => { + if (txType === TxType.DRepRetirement) { + return ; + } + + return ; +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss new file mode 100644 index 0000000000..ad8d4c179e --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss @@ -0,0 +1,15 @@ +@import '../../../../../../../../packages/common/src/ui/styles/theme.scss'; +@import '../../../../../../src/styles/rules/flex.scss'; + +.actions { + background-color: var(--bg-color-body); + @extend %flex-column; + justify-content: center; + gap: size_unit(1); + padding: size_unit(2) size_unit(3) size_unit(2) size_unit(3); + border-top: 2px solid var(--light-mode-light-grey-plus, var(--dark-mode-mid-grey)); + margin: size_unit(4) size_unit(-3) size_unit(-2) size_unit(-3); + position: sticky; + bottom: 0; + z-index: 10; +} diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx new file mode 100644 index 0000000000..3922016279 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx @@ -0,0 +1,47 @@ +import React, { useCallback } from 'react'; +import { Button } from '@lace/common'; +import { Wallet } from '@lace/cardano'; +import { useViewsFlowContext } from '@providers/ViewFlowProvider'; +import { useWalletStore } from '@stores'; +import { useDisallowSignTx, useOnBeforeUnload, useSignWithHardwareWallet } from '../hooks'; +import styles from './ConfirmTransactionFooterCommon.module.scss'; +import { useTranslation } from 'react-i18next'; + +type ConfirmTransactionFooterProps = { + errorMessage?: string; +}; + +export const ConfirmTransactionFooterCommon = ({ errorMessage }: ConfirmTransactionFooterProps): React.ReactElement => { + const { t } = useTranslation(); + const disallowSignTx = useDisallowSignTx(); + const { + utils: { setNextView } + } = useViewsFlowContext(); + const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); + const keyAgentType = useWalletStore((store) => store.getKeyAgentType()); + const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; + const handleSubmit = useCallback(async () => { + isUsingHardwareWallet ? await signWithHardwareWallet() : setNextView(); + }, [isUsingHardwareWallet, setNextView, signWithHardwareWallet]); + + useOnBeforeUnload(disallowSignTx); + + return ( +
+ + +
+ ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts new file mode 100644 index 0000000000..b86aa6c295 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts @@ -0,0 +1 @@ +export { ConfirmTransactionFooter } from './ConfirmTransactionFooter'; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx index 8049e90d44..a95e20f04a 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx @@ -13,7 +13,7 @@ const mockLovelacesToAdaString = jest.fn(); import { act, cleanup } from '@testing-library/react'; import { useCreateAssetList, - useIsOwnPubDRepKey, + useGetOwnPubDRepKeyHash, useOnBeforeUnload, useSignTxData, useSignWithHardwareWallet, diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx index 2d8a3f39ff..35fbb7d58c 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/utils.test.tsx @@ -17,7 +17,6 @@ import { certificateInspectorFactory, votingProceduresInspector, getTxType, - getOwnRetirementMessageKey, drepIDasBech32FromHash, pubDRepKeyToHash } from '../utils'; @@ -149,10 +148,4 @@ describe('Testing utils', () => { const pubDRepKeyHex = '_pubDRepKeyHex'; expect(await pubDRepKeyToHash(pubDRepKeyHex as Wallet.Crypto.Ed25519PublicKeyHex)).toEqual(pubDRepKeyHex); }); - - test('testing getOwnRetirementMessageKey', () => { - expect(getOwnRetirementMessageKey(undefined)).toEqual(''); - expect(getOwnRetirementMessageKey(true)).toEqual('core.DRepRetirement.isOwnRetirement'); - expect(getOwnRetirementMessageKey(false)).toEqual('core.DRepRetirement.isNotOwnRetirement'); - }); }); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts index b79f5452c3..55a3375e14 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts @@ -10,6 +10,7 @@ import { getTransactionAssetsId } from '@src/stores/slices'; import { AddressListType } from '@src/views/browser-view/features/activity'; import { TxType, allowSignTx, pubDRepKeyToHash, disallowSignTx, getTxType } from './utils'; import { GetSignTxData, SignTxData } from './types'; +import { useWalletStore } from '@stores'; export const useCreateAssetList = ({ assets, @@ -154,22 +155,27 @@ export const useOnBeforeUnload = (callBack: () => void): void => { }, [callBack]); }; -export const useIsOwnPubDRepKey = ( - getOwnPubDRepKey: () => Promise, - drepHash: Wallet.Crypto.Hash28ByteBase16 -): boolean => { - const [isOwnDRepKey, setIsOwnDRepKey] = useState(); +type UseIsOwnPubDRepKey = { + loading: boolean; + ownPubDRepKeyHash: Wallet.Crypto.Hash28ByteBase16; +}; + +export const useGetOwnPubDRepKeyHash = (): UseIsOwnPubDRepKey => { + const [ownPubDRepKeyHash, setOwnPubDRepKeyHash] = useState(); + const { inMemoryWallet } = useWalletStore(); useEffect(() => { + if (!inMemoryWallet) return; const get = async () => { - const ownPubDRepKey = await getOwnPubDRepKey(); + const ownPubDRepKey = await inMemoryWallet.getPubDRepKey(); const ownDRepKeyHash = await pubDRepKeyToHash(ownPubDRepKey); - setIsOwnDRepKey(drepHash === ownDRepKeyHash); + setOwnPubDRepKeyHash(ownDRepKeyHash); }; get(); - }, [getOwnPubDRepKey, drepHash]); + }, [inMemoryWallet]); - return isOwnDRepKey; + // TODO consider using Zustand or at least some common abstraction e.g. https://github.com/streamich/react-use/blob/master/src/useAsync.ts + return { loading: ownPubDRepKeyHash === undefined, ownPubDRepKeyHash }; }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts index 4a6e3d99d9..dc6893a046 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -131,10 +131,3 @@ export const pubDRepKeyToHash = async ( const drepKeyHex = (await pubDRepKey.hash()).hex(); return Wallet.Crypto.Hash28ByteBase16.fromEd25519KeyHashHex(drepKeyHex); }; - -export const getOwnRetirementMessageKey = (isOwnRetirement: boolean | undefined): string => { - if (isOwnRetirement === undefined) { - return ''; - } - return isOwnRetirement ? 'core.DRepRetirement.isOwnRetirement' : 'core.DRepRetirement.isNotOwnRetirement'; -}; diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index cc92351502..a6c0457a27 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -1154,8 +1154,14 @@ "metadata": "Metadata", "drepId": "DRep ID", "depositReturned": "Deposit returned", - "isOwnRetirement": "This is your DRep retirement.", - "isNotOwnRetirement": "The presented DRepID does not match your wallet's DRepID." + "drepIdMismatchModal": { + "title": "DRep ID Mismatch", + "description": "The DRep ID you are attempting to retire does not match the DRep ID associated with your wallet. Please review the details and ensure that you are retiring the correct DRep ID.", + "givenDRepId": "Presented DRep ID:", + "expectedDRepId": "Your Wallet's DRep ID:", + "confirm": "Proceed", + "cancel": "Cancel" + } }, "DRepUpdate": { "title": "Confirm DRep Update", From 86ccb0f4d9fd127bd95ea37f6bf10d6b99cd04e3 Mon Sep 17 00:00:00 2001 From: "przemyslaw.wlodek" Date: Tue, 28 Nov 2023 15:09:35 +0100 Subject: [PATCH 2/9] test(extension): fix part of the tests for confirm-transaction feature --- .../__tests__/ConfirmTransaction.test.tsx | 53 +++++++++++-------- .../components/confirm-transaction/hooks.ts | 5 +- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx index 37cc77521a..afe24c1939 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx @@ -57,6 +57,11 @@ jest.mock('@src/stores', () => ({ useWalletStore: mockUseWalletStore })); +jest.mock('@stores', () => ({ + ...jest.requireActual('@stores'), + useWalletStore: mockUseWalletStore +})); + jest.mock('@cardano-sdk/web-extension', () => { const original = jest.requireActual('@cardano-sdk/web-extension'); return { @@ -182,13 +187,15 @@ describe('Testing ConfirmTransaction component', () => { mockGetKeyAgentType.mockReset(); mockGetKeyAgentType.mockReturnValue(Wallet.KeyManagement.KeyAgentType.InMemory); mockUseWalletStore.mockReset(); - mockUseWalletStore.mockImplementation(() => ({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - })); + mockUseWalletStore.mockImplementation((selector) => + selector({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + }) + ); mockGetTxType.mockReset(); mockGetTxType.mockReturnValue(txType); mockGetTitleKey.mockReset(); @@ -245,13 +252,15 @@ describe('Testing ConfirmTransaction component', () => { mockGetKeyAgentType.mockReset(); mockGetKeyAgentType.mockReturnValue(Wallet.KeyManagement.KeyAgentType.Ledger); mockUseWalletStore.mockReset(); - mockUseWalletStore.mockImplementation(() => ({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - })); + mockUseWalletStore.mockImplementation((selector) => + selector({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + }) + ); const signTxData = { tx: 'signTxDataTx' }; mockConsumeRemoteApi.mockReset(); @@ -280,13 +289,15 @@ describe('Testing ConfirmTransaction component', () => { test('should disable confirm button and show proper error if getSignTxData throws', async () => { let queryByTestId: any; const txType = 'txType'; - mockUseWalletStore.mockImplementation(() => ({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - })); + mockUseWalletStore.mockImplementation((selector) => + selector({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + }) + ); mockConsumeRemoteApi.mockReset(); mockConsumeRemoteApi.mockReturnValue({ getSignTxData: async () => await Promise.reject(error) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts index 55a3375e14..7a78be4ac7 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/hooks.ts @@ -66,6 +66,7 @@ export const useSignTxData = (getSignTxData: GetSignTxData): { signTxData?: Sign }) .catch((error) => { setErrorMessage(error); + // TODO: consider mocking or removing this log console.error(error); }); }, [getSignTxData, setSignTxData, setErrorMessage]); @@ -155,12 +156,12 @@ export const useOnBeforeUnload = (callBack: () => void): void => { }, [callBack]); }; -type UseIsOwnPubDRepKey = { +type UseGetOwnPubDRepKeyHash = { loading: boolean; ownPubDRepKeyHash: Wallet.Crypto.Hash28ByteBase16; }; -export const useGetOwnPubDRepKeyHash = (): UseIsOwnPubDRepKey => { +export const useGetOwnPubDRepKeyHash = (): UseGetOwnPubDRepKeyHash => { const [ownPubDRepKeyHash, setOwnPubDRepKeyHash] = useState(); const { inMemoryWallet } = useWalletStore(); From 022867b5237acd32e961857bb7501af6644afa0a Mon Sep 17 00:00:00 2001 From: "przemyslaw.wlodek" Date: Tue, 28 Nov 2023 11:02:39 +0100 Subject: [PATCH 3/9] feat(extension): add drep retirement id mismatch modal --- .../__tests__/hooks.test.tsx | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx index a95e20f04a..174046aa07 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/hooks.test.tsx @@ -10,6 +10,7 @@ const mockGetTransactionAssetsId = jest.fn(); const mockGetAssetsInformation = jest.fn(); const mockCalculateAssetBalance = jest.fn(); const mockLovelacesToAdaString = jest.fn(); +const mockUseWalletStore = jest.fn(); import { act, cleanup } from '@testing-library/react'; import { useCreateAssetList, @@ -29,6 +30,11 @@ import { AddressListType } from '@src/views/browser-view/features/activity'; import { WalletInfo } from '@src/types'; import * as Core from '@cardano-sdk/core'; +jest.mock('@stores', () => ({ + ...jest.requireActual('@stores'), + useWalletStore: mockUseWalletStore +})); + jest.mock('@cardano-sdk/core', () => ({ ...jest.requireActual('@cardano-sdk/core'), createTxInspector: jest.fn() @@ -391,27 +397,25 @@ describe('Testing hooks', () => { removeEventListeners(); }); - test('useIsOwnPubDRepKey', async () => { + test('useGetOwnPubDRepKeyHash', async () => { const ed25519PublicKeyHexMock = 'ed25519PublicKeyHexMock'; mockPubDRepKeyToHash.mockReset(); mockPubDRepKeyToHash.mockImplementation(async (val: Wallet.Crypto.Ed25519PublicKeyHex) => await val); - - const hook = renderHook(() => - useIsOwnPubDRepKey( - async () => (await ed25519PublicKeyHexMock) as Wallet.Crypto.Ed25519PublicKeyHex, - ed25519PublicKeyHexMock as Wallet.Crypto.Hash28ByteBase16 - ) - ); - await hook.waitFor(() => { - expect(hook.result.current).toBe(true); + mockUseWalletStore.mockReset(); + mockUseWalletStore.mockReturnValue({ + inMemoryWallet: { + getPubDRepKey: jest.fn(async () => await ed25519PublicKeyHexMock) + } }); - mockPubDRepKeyToHash.mockReset(); - mockPubDRepKeyToHash.mockImplementation(async () => await 1); - hook.rerender(); + let hook: any; + await act(async () => { + hook = renderHook(() => useGetOwnPubDRepKeyHash()); + expect(hook.result.current.loading).toEqual(true); + }); await hook.waitFor(() => { - expect(hook.result.current).toBe(false); + expect(hook.result.current.ownPubDRepKeyHash).toEqual(ed25519PublicKeyHexMock); }); }); }); From 3c4a2b40bdf86c7f98de2dc1ec4966013eb3315d Mon Sep 17 00:00:00 2001 From: "przemyslaw.wlodek" Date: Tue, 28 Nov 2023 15:47:12 +0100 Subject: [PATCH 4/9] refactor(extension): reduce code duplication in ConfirmTransactionFooter --- .../ConfirmDRepRetirementFooter.tsx | 59 ++++++------------- .../ConfirmTransactionFooterCommon.tsx | 20 +++++-- 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx index 571ec018a8..4fa1301ed6 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx @@ -1,14 +1,11 @@ -import React, { useCallback, useState } from 'react'; -import { Button } from '@lace/common'; +/* eslint-disable unicorn/no-null */ +import React, { useState } from 'react'; import { Wallet } from '@lace/cardano'; -import { useViewsFlowContext } from '@providers/ViewFlowProvider'; -import { useWalletStore } from '@stores'; -import { useDisallowSignTx, useGetOwnPubDRepKeyHash, useOnBeforeUnload, useSignWithHardwareWallet } from '../hooks'; +import { useGetOwnPubDRepKeyHash } from '../hooks'; import { certificateInspectorFactory } from '../utils'; import { SignTxData } from '../types'; -import styles from './ConfirmTransactionFooterCommon.module.scss'; -import { useTranslation } from 'react-i18next'; import { ConfirmDRepRetirementIdMismatchModal } from '@src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal'; +import { ConfirmTransactionFooterCommon } from '@src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon'; type ConfirmTransactionFooterProps = { signTxData?: SignTxData; @@ -19,51 +16,31 @@ export const ConfirmDRepRetirementFooter = ({ signTxData, errorMessage }: ConfirmTransactionFooterProps): React.ReactElement => { - const { t } = useTranslation(); - const disallowSignTx = useDisallowSignTx(); - const { - utils: { setNextView } - } = useViewsFlowContext(); - const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); - const keyAgentType = useWalletStore((store) => store.getKeyAgentType()); - const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; - const [dRepIdMismatchModalOpen, setDRepIdMismatchModalOpen] = useState(false); - const handleSubmit = useCallback(async () => { - isUsingHardwareWallet ? await signWithHardwareWallet() : setNextView(); - }, [isUsingHardwareWallet, setNextView, signWithHardwareWallet]); + const [dRepIdMismatchModalAcceptCallback, setDRepIdMismatchModalAcceptCallback] = useState<() => void>(null); const { dRepCredential: { hash: transactionDrepKeyHash } } = certificateInspectorFactory( Wallet.Cardano.CertificateType.UnregisterDelegateRepresentative )(signTxData.tx); const { loading, ownPubDRepKeyHash } = useGetOwnPubDRepKeyHash(); - const isOwnDRepKey = transactionDrepKeyHash === ownPubDRepKeyHash; - - useOnBeforeUnload(disallowSignTx); + const isOwnDRepKey = transactionDrepKeyHash === 'ownPubDRepKeyHash'; return ( -
+ <> setDRepIdMismatchModalOpen(false)} + onConfirm={dRepIdMismatchModalAcceptCallback} + onCancel={() => setDRepIdMismatchModalAcceptCallback(null)} + /> + setDRepIdMismatchModalAcceptCallback(() => handleAccept) + } /> - - -
+ ); }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx index 3922016279..3be7f228e8 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx @@ -9,9 +9,15 @@ import { useTranslation } from 'react-i18next'; type ConfirmTransactionFooterProps = { errorMessage?: string; + onBeforeSubmit?: (submit: () => void) => void; + loading?: boolean; }; -export const ConfirmTransactionFooterCommon = ({ errorMessage }: ConfirmTransactionFooterProps): React.ReactElement => { +export const ConfirmTransactionFooterCommon = ({ + loading, + errorMessage, + onBeforeSubmit = (fn) => fn() +}: ConfirmTransactionFooterProps): React.ReactElement => { const { t } = useTranslation(); const disallowSignTx = useDisallowSignTx(); const { @@ -20,9 +26,13 @@ export const ConfirmTransactionFooterCommon = ({ errorMessage }: ConfirmTransact const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); const keyAgentType = useWalletStore((store) => store.getKeyAgentType()); const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; - const handleSubmit = useCallback(async () => { - isUsingHardwareWallet ? await signWithHardwareWallet() : setNextView(); - }, [isUsingHardwareWallet, setNextView, signWithHardwareWallet]); + const handleSubmit = useCallback( + () => + onBeforeSubmit(async () => { + isUsingHardwareWallet ? await signWithHardwareWallet() : setNextView(); + }), + [isUsingHardwareWallet, setNextView, signWithHardwareWallet, onBeforeSubmit] + ); useOnBeforeUnload(disallowSignTx); @@ -31,7 +41,7 @@ export const ConfirmTransactionFooterCommon = ({ errorMessage }: ConfirmTransact - - - - ); -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss index 6f5d3c5f26..1a7a65a097 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss @@ -5,3 +5,18 @@ justify-content: space-between; padding-top: size_unit(2); } + +.actions { + @extend %flex-column; + background-color: var(--bg-color-body); + gap: size_unit(1); + padding: size_unit(2) size_unit(3) size_unit(2) size_unit(3); + border-top: 2px solid var(--light-mode-light-grey-plus, var(--dark-mode-mid-grey)); + margin: size_unit(4) size_unit(-3) size_unit(-2) size_unit(-3); + position: sticky; + bottom: 0; + z-index: 10; + .actionBtn { + width: 100%; + } +} diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx index f90eea8d72..eafa747bbf 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import React, { useMemo } from 'react'; +import React, { useMemo, useState } from 'react'; import { Button, PostHogAction } from '@lace/common'; import { useTranslation } from 'react-i18next'; import { Layout } from '../Layout'; @@ -38,7 +38,8 @@ export const ConfirmTransaction = (): React.ReactElement => { ); const { getKeyAgentType } = useWalletStore(); const analytics = useAnalyticsContext(); - const { signTxData, errorMessage } = useSignTxData(dappDataApi.getSignTxData); + const { signTxData, errorMessage: getSignTxDataError } = useSignTxData(dappDataApi.getSignTxData); + const [confirmTransactionError, setConfirmTransactionError] = useState(false); const keyAgentType = getKeyAgentType(); const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; const disallowSignTx = useDisallowSignTx(); @@ -62,29 +63,36 @@ export const ConfirmTransaction = (): React.ReactElement => { useOnBeforeUnload(disallowSignTx); return ( - - -
- - -
+ + setConfirmTransactionError(true)} + errorMessage={getSignTxDataError} + /> + {!confirmTransactionError && ( +
+ + +
+ )}
); }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx index eb931efab5..4d35efc983 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx @@ -13,9 +13,10 @@ interface Props { txType?: Wallet.Cip30TxType; signTxData?: SignTxData; errorMessage?: string; + onError?: () => void; } -export const ConfirmTransactionContent = ({ txType, signTxData, errorMessage }: Props): React.ReactElement => { +export const ConfirmTransactionContent = ({ txType, signTxData, onError, errorMessage }: Props): React.ReactElement => { if (!signTxData) { return ; } @@ -23,7 +24,7 @@ export const ConfirmTransactionContent = ({ txType, signTxData, errorMessage }: return ; } if (txType === Wallet.Cip30TxType.DRepRetirement) { - return ; + return ; } if (txType === Wallet.Cip30TxType.DRepUpdate) { return ; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx deleted file mode 100644 index a2b101e448..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmDRepRetirementFooter.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* eslint-disable unicorn/no-null */ -import React, { useState } from 'react'; -import { Wallet } from '@lace/cardano'; -import { useGetOwnPubDRepKeyHash } from '../hooks'; -import { certificateInspectorFactory } from '../utils'; -import { SignTxData } from '../types'; -import { ConfirmDRepRetirementIdMismatchModal } from '@src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementIdMismatchModal'; -import { ConfirmTransactionFooterCommon } from '@src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon'; - -type ConfirmTransactionFooterProps = { - signTxData?: SignTxData; - errorMessage?: string; -}; - -export const ConfirmDRepRetirementFooter = ({ - signTxData, - errorMessage -}: ConfirmTransactionFooterProps): React.ReactElement => { - const [dRepIdMismatchModalAcceptCallback, setDRepIdMismatchModalAcceptCallback] = useState<() => void>(null); - const { - dRepCredential: { hash: transactionDrepKeyHash } - } = certificateInspectorFactory( - Wallet.Cardano.CertificateType.UnregisterDelegateRepresentative - )(signTxData.tx); - const { loading, ownPubDRepKeyHash } = useGetOwnPubDRepKeyHash(); - const isOwnDRepKey = transactionDrepKeyHash === ownPubDRepKeyHash; - - return ( - <> - setDRepIdMismatchModalAcceptCallback(null)} - /> - setDRepIdMismatchModalAcceptCallback(() => handleAccept) - } - /> - - ); -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx deleted file mode 100644 index 208f7beecc..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooter.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { TxType } from '../utils'; -import { SignTxData } from '../types'; -import { ConfirmTransactionFooterCommon } from './ConfirmTransactionFooterCommon'; -import { ConfirmDRepRetirementFooter } from './ConfirmDRepRetirementFooter'; - -type ConfirmTransactionFooterProps = { - txType?: TxType; - signTxData?: SignTxData; - errorMessage?: string; -}; - -export const ConfirmTransactionFooter = ({ - txType, - signTxData, - errorMessage -}: ConfirmTransactionFooterProps): React.ReactElement => { - if (txType === TxType.DRepRetirement) { - return ; - } - - return ; -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss deleted file mode 100644 index ad8d4c179e..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -@import '../../../../../../../../packages/common/src/ui/styles/theme.scss'; -@import '../../../../../../src/styles/rules/flex.scss'; - -.actions { - background-color: var(--bg-color-body); - @extend %flex-column; - justify-content: center; - gap: size_unit(1); - padding: size_unit(2) size_unit(3) size_unit(2) size_unit(3); - border-top: 2px solid var(--light-mode-light-grey-plus, var(--dark-mode-mid-grey)); - margin: size_unit(4) size_unit(-3) size_unit(-2) size_unit(-3); - position: sticky; - bottom: 0; - z-index: 10; -} diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx deleted file mode 100644 index 18ed161047..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/ConfirmTransactionFooterCommon.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useCallback } from 'react'; -import { Button } from '@lace/common'; -import { Wallet } from '@lace/cardano'; -import { useViewsFlowContext } from '@providers/ViewFlowProvider'; -import { useWalletStore } from '@stores'; -import { useDisallowSignTx, useOnBeforeUnload, useSignWithHardwareWallet } from '../hooks'; -import styles from './ConfirmTransactionFooterCommon.module.scss'; -import { useTranslation } from 'react-i18next'; - -type ConfirmTransactionFooterProps = { - errorMessage?: string; - onBeforeSubmit?: (submit: () => Promise) => void; - loading?: boolean; -}; - -export const ConfirmTransactionFooterCommon = ({ - loading, - errorMessage, - onBeforeSubmit = (fn) => fn() -}: ConfirmTransactionFooterProps): React.ReactElement => { - const { t } = useTranslation(); - const disallowSignTx = useDisallowSignTx(); - const { - utils: { setNextView } - } = useViewsFlowContext(); - const { isConfirmingTx, signWithHardwareWallet } = useSignWithHardwareWallet(); - const keyAgentType = useWalletStore((store) => store.getKeyAgentType()); - const isUsingHardwareWallet = keyAgentType !== Wallet.KeyManagement.KeyAgentType.InMemory; - const handleSubmit = useCallback( - () => - onBeforeSubmit(async () => { - isUsingHardwareWallet ? await signWithHardwareWallet() : setNextView(); - }), - [isUsingHardwareWallet, setNextView, signWithHardwareWallet, onBeforeSubmit] - ); - - useOnBeforeUnload(disallowSignTx); - - return ( -
- - -
- ); -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts deleted file mode 100644 index b86aa6c295..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionFooter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ConfirmTransactionFooter } from './ConfirmTransactionFooter'; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepIdMismatch.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepIdMismatch.tsx new file mode 100644 index 0000000000..4dddfd1e64 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepIdMismatch.tsx @@ -0,0 +1,38 @@ +import React, { useEffect } from 'react'; +import { Image } from 'antd'; +import { useTranslation } from 'react-i18next'; +import Empty from '../../../../assets/icons/empty.svg'; +import styles from '../Layout.module.scss'; +import { Button } from '@lace/common'; + +type DRepIdMismatchProps = { + onMount: () => void; +}; + +export const DRepIdMismatch = ({ onMount }: DRepIdMismatchProps): React.ReactElement => { + const { t } = useTranslation(); + + useEffect(() => { + onMount(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( +
+
+ +
+ {t('core.DRepRetirement.drepIdMismatchScreen.title')} +
+
+ {t('core.DRepRetirement.drepIdMismatchScreen.description')} +
+
+
+ +
+
+ ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx index bb0fe2b214..6206d6a1a9 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx @@ -2,11 +2,21 @@ /* eslint-disable unicorn/no-null */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable import/imports-first */ + +import { UserPromptService } from '@lib/scripts/background/services'; +import { ExposeApiProps } from '@cardano-sdk/web-extension'; + const mockUseWalletStore = jest.fn(); const t = jest.fn().mockImplementation((res) => res); const mockUseTranslation = jest.fn(() => ({ t })); const mockConfirmDRepRetirement = jest.fn(); -const mockPubDRepKeyToHash = jest.fn(); +const mockDRepIdMismatch = jest.fn(); +const mockUseGetOwnPubDRepKeyHash = jest.fn(); +const mockExposeApi = jest.fn((props: ExposeApiProps>) => { + let returnValue; + props.api$.forEach((v) => (returnValue = v.allowSignTx())); + return returnValue; +}); import * as React from 'react'; import { cleanup, render } from '@testing-library/react'; import { ConfirmDRepRetirementContainer } from '../ConfirmDRepRetirementContainer'; @@ -29,7 +39,6 @@ import { postHogClientMocks } from '@src/utils/mocks/test-helpers'; import { buildMockTx } from '@src/utils/mocks/tx'; import { Wallet } from '@lace/cardano'; import BigNumber from 'bignumber.js'; - const LOVELACE_VALUE = 1_000_000; const DEFAULT_DECIMALS = 2; @@ -55,6 +64,24 @@ const cardanoCoinMock = { symbol: 'cardanoCoinMockSymbol' }; +jest.mock('@cardano-sdk/web-extension', () => { + const original = jest.requireActual('@cardano-sdk/web-extension'); + return { + __esModule: true, + ...original, + exposeApi: mockExposeApi + }; +}); + +jest.mock('../hooks.ts', () => { + const original = jest.requireActual('../hooks.ts'); + return { + __esModule: true, + ...original, + useGetOwnPubDRepKeyHash: mockUseGetOwnPubDRepKeyHash + }; +}); + jest.mock('@src/stores', () => ({ ...jest.requireActual('@src/stores'), useWalletStore: mockUseWalletStore @@ -69,21 +96,21 @@ jest.mock('@lace/core', () => { }; }); -jest.mock('react-i18next', () => { - const original = jest.requireActual('react-i18next'); +jest.mock('../DRepIdMismatch', () => { + const original = jest.requireActual('@lace/core'); return { __esModule: true, ...original, - useTranslation: mockUseTranslation + DRepIdMismatch: mockDRepIdMismatch }; }); -jest.mock('../utils.ts', () => { - const original = jest.requireActual('../utils.ts'); +jest.mock('react-i18next', () => { + const original = jest.requireActual('react-i18next'); return { __esModule: true, ...original, - pubDRepKeyToHash: mockPubDRepKeyToHash + useTranslation: mockUseTranslation }; }); @@ -114,6 +141,11 @@ const getWrapper = describe('Testing ConfirmDRepRetirementContainer component', () => { beforeEach(() => { mockUseWalletStore.mockReset(); + mockExposeApi.mockRestore(); + mockUseGetOwnPubDRepKeyHash.mockImplementationOnce(() => ({ + loading: false, + ownPubDRepKeyHash: hash + })); mockUseWalletStore.mockImplementation(() => ({ inMemoryWallet, walletUI: { cardanoCoin: cardanoCoinMock }, @@ -121,8 +153,8 @@ describe('Testing ConfirmDRepRetirementContainer component', () => { })); mockConfirmDRepRetirement.mockReset(); mockConfirmDRepRetirement.mockReturnValue(); - mockPubDRepKeyToHash.mockReset(); - mockPubDRepKeyToHash.mockImplementation(async () => await '123'); + mockDRepIdMismatch.mockReset(); + mockDRepIdMismatch.mockReturnValue(); mockUseTranslation.mockReset(); mockUseTranslation.mockImplementation(() => ({ t })); }); @@ -150,12 +182,14 @@ describe('Testing ConfirmDRepRetirementContainer component', () => { certificates: [certificate] }); const errorMessage = 'errorMessage'; + // eslint-disable-next-line unicorn/consistent-function-scoping + const onErrorMock = jest.fn(); test('should render ConfirmDRepRetirementContainer component with proper props', async () => { let queryByTestId: any; await act(async () => { ({ queryByTestId } = render( - , + , { wrapper: getWrapper() } @@ -186,13 +220,14 @@ describe('Testing ConfirmDRepRetirementContainer component', () => { }); test('should render ConfirmDRepRetirementContainer component with proper error for own retirement', async () => { - mockPubDRepKeyToHash.mockReset(); - mockPubDRepKeyToHash.mockImplementation(async (_hash) => await _hash); let queryByTestId: any; await act(async () => { - ({ queryByTestId } = render(, { - wrapper: getWrapper() - })); + ({ queryByTestId } = render( + , + { + wrapper: getWrapper() + } + )); }); expect(queryByTestId('ConfirmDRepRetirementContainer')).toBeInTheDocument(); @@ -202,19 +237,21 @@ describe('Testing ConfirmDRepRetirementContainer component', () => { }); test('should render ConfirmDRepRetirementContainer component with proper error for not own retirement', async () => { - mockPubDRepKeyToHash.mockReset(); - mockPubDRepKeyToHash.mockImplementation(async () => await ''); + mockUseGetOwnPubDRepKeyHash.mockReset(); + mockUseGetOwnPubDRepKeyHash.mockImplementation(() => ({ + loading: false, + ownPubDRepKeyHash: Crypto.Hash28ByteBase16(Buffer.from('WRONG_dRepCredentialHashdRep').toString('hex')) + })); let queryByTestId: any; await act(async () => { - ({ queryByTestId } = render(, { - wrapper: getWrapper() - })); + ({ queryByTestId } = render( + , + { + wrapper: getWrapper() + } + )); }); - expect(queryByTestId('ConfirmDRepRetirementContainer')).toBeInTheDocument(); - - expect( - mockConfirmDRepRetirement.mock.calls[mockConfirmDRepRetirement.mock.calls.length - 1][0].errorMessage - ).toEqual(t('core.DRepRetirement.isNotOwnRetirement')); + expect(queryByTestId('DRepIdMismatch')).toBeInTheDocument(); }); }); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx index 4314f74333..6be8a2a2c9 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmTransaction.test.tsx @@ -170,8 +170,6 @@ describe('Testing ConfirmTransaction component', () => { mockUseViewsFlowContext.mockReturnValue({ utils: {} }); mockConfirmTransactionContent.mockReset(); mockConfirmTransactionContent.mockImplementation(() => ); - mockConfirmTransactionContent.mockReset(); - mockConfirmTransactionContent.mockImplementation(() => ); }); afterEach(() => { @@ -187,15 +185,13 @@ describe('Testing ConfirmTransaction component', () => { mockGetKeyAgentType.mockReset(); mockGetKeyAgentType.mockReturnValue(Wallet.KeyManagement.KeyAgentType.InMemory); mockUseWalletStore.mockReset(); - mockUseWalletStore.mockImplementation((selector) => - selector({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - }) - ); + mockUseWalletStore.mockImplementation(() => ({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + })); mockGetTxType.mockReset(); mockGetTxType.mockReturnValue(txType); mockGetTitleKey.mockReset(); @@ -224,7 +220,9 @@ describe('Testing ConfirmTransaction component', () => { expect(mockConfirmTransactionContent).toHaveBeenLastCalledWith( { txType, - signTxData + signTxData, + errorMessage: undefined, + onError: expect.any(Function) }, {} ); @@ -252,15 +250,13 @@ describe('Testing ConfirmTransaction component', () => { mockGetKeyAgentType.mockReset(); mockGetKeyAgentType.mockReturnValue(Wallet.KeyManagement.KeyAgentType.Ledger); mockUseWalletStore.mockReset(); - mockUseWalletStore.mockImplementation((selector) => - selector({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - }) - ); + mockUseWalletStore.mockImplementation(() => ({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + })); const signTxData = { tx: { id: 'test-tx-id' } }; mockConsumeRemoteApi.mockReset(); @@ -289,15 +285,13 @@ describe('Testing ConfirmTransaction component', () => { test('should disable confirm button and show proper error if getSignTxData throws', async () => { let queryByTestId: any; const txType = 'txType'; - mockUseWalletStore.mockImplementation((selector) => - selector({ - getKeyAgentType: mockGetKeyAgentType, - inMemoryWallet, - walletUI: {}, - walletInfo: {}, - blockchainProvider: { assetProvider } - }) - ); + mockUseWalletStore.mockImplementation(() => ({ + getKeyAgentType: mockGetKeyAgentType, + inMemoryWallet, + walletUI: {}, + walletInfo: {}, + blockchainProvider: { assetProvider } + })); mockConsumeRemoteApi.mockReset(); mockConsumeRemoteApi.mockReturnValue({ getSignTxData: async () => await Promise.reject(error) @@ -311,7 +305,10 @@ describe('Testing ConfirmTransaction component', () => { }); expect(queryByTestId('ConfirmTransactionContent')).toBeInTheDocument(); - expect(mockConfirmTransactionContent).toHaveBeenLastCalledWith({ errorMessage: error }, {}); + expect(mockConfirmTransactionContent).toHaveBeenLastCalledWith( + { errorMessage: error, onError: expect.any(Function), signTxData: undefined, txType: undefined }, + {} + ); expect(queryByTestId(testIds.dappTransactionConfirm).closest('button')).toHaveAttribute('disabled'); }); }); diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index c0216e320e..001454e8ee 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -1168,12 +1168,9 @@ "metadata": "Metadata", "drepId": "DRep ID", "depositReturned": "Deposit returned", - "drepIdMismatchModal": { - "title": "DRep ID Mismatch", - "description": "The DRep ID you are attempting to retire does not match the DRep ID associated with your wallet. Please review the details and ensure that you are retiring the correct DRep ID.", - "givenDRepId": "Presented DRep ID:", - "expectedDRepId": "Your Wallet's DRep ID:", - "confirm": "Proceed", + "drepIdMismatchScreen": { + "title": "DRep ID mismatch", + "description": "The presented DRepID does not match your wallet's DRepID", "cancel": "Cancel" } }, diff --git a/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx b/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx index e223e57d02..753bf49e60 100644 --- a/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx +++ b/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx @@ -97,7 +97,6 @@ export const DappConnectorView = (): React.ReactElement => { return ( - From 996e556ad678ef9d0a3416994f7d2107513da289 Mon Sep 17 00:00:00 2001 From: "przemyslaw.wlodek" Date: Tue, 5 Dec 2023 15:05:40 +0100 Subject: [PATCH 8/9] refactor(extension): introduce common DappError page + fix design discrepancies --- .../features/dapp/components/DappError.tsx | 61 +++++++++++++++++++ .../dapp/components/DappTransactionFail.tsx | 4 +- .../components/DappTransactionSuccess.tsx | 4 +- .../dapp/components/Layout.module.scss | 7 ++- .../src/features/dapp/components/NoWallet.tsx | 35 ----------- .../ConfirmDRepRetirementContainer.tsx | 11 +++- .../ConfirmTransaction.module.scss | 4 ++ .../ConfirmTransaction.tsx | 7 ++- .../confirm-transaction/DRepIdMismatch.tsx | 38 ------------ .../ConfirmDRepRetirementContainer.test.tsx | 14 ++--- .../src/features/dapp/components/index.ts | 1 - .../src/lib/translations/en.json | 3 +- .../src/routes/DappConnectorView.tsx | 19 +++++- 13 files changed, 114 insertions(+), 94 deletions(-) create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/DappError.tsx delete mode 100644 apps/browser-extension-wallet/src/features/dapp/components/NoWallet.tsx delete mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepIdMismatch.tsx diff --git a/apps/browser-extension-wallet/src/features/dapp/components/DappError.tsx b/apps/browser-extension-wallet/src/features/dapp/components/DappError.tsx new file mode 100644 index 0000000000..438445600d --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/DappError.tsx @@ -0,0 +1,61 @@ +import React, { ReactNode, useCallback, useEffect } from 'react'; +import { Image } from 'antd'; +import { useTranslation } from 'react-i18next'; +import Empty from '../../../assets/icons/empty.svg'; +import styles from './Layout.module.scss'; +import { Button } from '@lace/common'; + +type DappErrorProps = { + title: string; + description: ReactNode; + closeButtonLabel?: string; + onCloseClick?: () => void; + onMount?: () => void; + containerTestId: string; + imageTestId: string; + titleTestId: string; + descriptionTestId: string; + closeButtonTestId: string; +}; +export const DappError = ({ + title, + description, + closeButtonLabel, + onCloseClick, + onMount, + containerTestId, + imageTestId, + titleTestId, + descriptionTestId, + closeButtonTestId +}: DappErrorProps): React.ReactElement => { + const { t } = useTranslation(); + const handleClose = useCallback(() => { + if (onCloseClick) onCloseClick(); + window.close(); + }, [onCloseClick]); + + useEffect(() => { + if (onMount) onMount(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( +
+
+ +
+ {title} +
+
+ {description} +
+
+
+ +
+
+ ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionFail.tsx b/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionFail.tsx index e008f2810f..465bbf40b7 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionFail.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionFail.tsx @@ -24,8 +24,8 @@ export const DappTransactionFail = (): React.ReactElement => { }, [analytics]); return ( -
-
+
+
{t('dapp.sign.failure.title')}
{t('dapp.sign.failure.description')}
diff --git a/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionSuccess.tsx b/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionSuccess.tsx index c69b4bf667..42650cdf24 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionSuccess.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/DappTransactionSuccess.tsx @@ -25,8 +25,8 @@ export const DappTransactionSuccess = (): React.ReactElement => { }, [analytics]); return ( -
-
+
+
{t('browserView.transaction.success.youCanSafelyCloseThisPanel')} diff --git a/apps/browser-extension-wallet/src/features/dapp/components/Layout.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/Layout.module.scss index edad913a6a..58262eb769 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/Layout.module.scss +++ b/apps/browser-extension-wallet/src/features/dapp/components/Layout.module.scss @@ -26,7 +26,7 @@ padding-top: size_unit(4); } -.noWalletContainer { +.dappErrorContainer { align-items: center; display: flex; flex-direction: column; @@ -34,7 +34,7 @@ justify-content: space-between; width: 100%; - .noWalletContent { + .dappErrorContent { padding: 0 size_unit(3); display: flex; flex: 1; @@ -45,7 +45,7 @@ .heading { color: var(--text-color-secondary); font-size: var(--bodyLarge); - font-weight: 800; + font-weight: 600; letter-spacing: 0.02em; line-height: size_unit(3); margin-top: size_unit(2); @@ -55,6 +55,7 @@ .description { color: var(--text-color-secondary); font-size: var(--bodySmall); + font-weight: 500; letter-spacing: 0.02em; line-height: size_unit(3); margin-top: size_unit(2); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/NoWallet.tsx b/apps/browser-extension-wallet/src/features/dapp/components/NoWallet.tsx deleted file mode 100644 index 86050bb7ea..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/NoWallet.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import { Image } from 'antd'; -import { useTranslation } from 'react-i18next'; -import Empty from '../../../assets/icons/empty.svg'; -import styles from './Layout.module.scss'; -import { Button } from '@lace/common'; -import { tabs } from 'webextension-polyfill'; - -const openCreatePage = () => { - tabs.create({ url: 'app.html#/setup' }); - window.close(); -}; - -export const NoWallet = (): React.ReactElement => { - const { t } = useTranslation(); - - return ( -
-
- -
- {t('dapp.noWallet.heading')} -
-
- {t('dapp.noWallet.description')} -
-
-
- -
-
- ); -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx index 14b8c37f5e..2727c88121 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx @@ -7,13 +7,13 @@ import { useWalletStore } from '@src/stores'; import { SignTxData } from './types'; import { useGetOwnPubDRepKeyHash } from './hooks'; import { Skeleton } from 'antd'; -import { DRepIdMismatch } from './DRepIdMismatch'; import { exposeApi, RemoteApiPropertyType } from '@cardano-sdk/web-extension'; import { UserPromptService } from '@lib/scripts/background/services'; import { of } from 'rxjs'; import { ApiError, APIErrorCode } from '@cardano-sdk/dapp-connector'; import { DAPP_CHANNELS } from '@utils/constants'; import { runtime } from 'webextension-polyfill'; +import { DappError } from '../DappError'; interface Props { signTxData: SignTxData; @@ -56,11 +56,18 @@ export const ConfirmDRepRetirementContainer = ({ signTxData, onError, errorMessa if (isNotOwnDRepKey) { return ( - { disallowSignTx(); onError(); }} + containerTestId="drep-id-mismatch-container" + imageTestId="drep-id-mismatch-image" + titleTestId="drep-id-mismatch-heading" + descriptionTestId="drep-id-mismatch-description" + closeButtonTestId="drep-id-mismatch-close-button" /> ); } diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss index 1a7a65a097..3376b96ac5 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.module.scss @@ -6,6 +6,10 @@ padding-top: size_unit(2); } +.layoutError { + padding: 0; +} + .actions { @extend %flex-column; background-color: var(--bg-color-body); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx index eafa747bbf..e17e48769d 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransaction.tsx @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import React, { useMemo, useState } from 'react'; +import cn from 'classnames'; import { Button, PostHogAction } from '@lace/common'; import { useTranslation } from 'react-i18next'; import { Layout } from '../Layout'; @@ -63,7 +64,11 @@ export const ConfirmTransaction = (): React.ReactElement => { useOnBeforeUnload(disallowSignTx); return ( - + void; -}; - -export const DRepIdMismatch = ({ onMount }: DRepIdMismatchProps): React.ReactElement => { - const { t } = useTranslation(); - - useEffect(() => { - onMount(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( -
-
- -
- {t('core.DRepRetirement.drepIdMismatchScreen.title')} -
-
- {t('core.DRepRetirement.drepIdMismatchScreen.description')} -
-
-
- -
-
- ); -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx index 6206d6a1a9..ce95751ae9 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx @@ -10,7 +10,7 @@ const mockUseWalletStore = jest.fn(); const t = jest.fn().mockImplementation((res) => res); const mockUseTranslation = jest.fn(() => ({ t })); const mockConfirmDRepRetirement = jest.fn(); -const mockDRepIdMismatch = jest.fn(); +const mockDappError = jest.fn(); const mockUseGetOwnPubDRepKeyHash = jest.fn(); const mockExposeApi = jest.fn((props: ExposeApiProps>) => { let returnValue; @@ -96,12 +96,12 @@ jest.mock('@lace/core', () => { }; }); -jest.mock('../DRepIdMismatch', () => { - const original = jest.requireActual('@lace/core'); +jest.mock('../DappError', () => { + const original = jest.requireActual('../DappError'); return { __esModule: true, ...original, - DRepIdMismatch: mockDRepIdMismatch + DappError: mockDappError }; }); @@ -153,8 +153,8 @@ describe('Testing ConfirmDRepRetirementContainer component', () => { })); mockConfirmDRepRetirement.mockReset(); mockConfirmDRepRetirement.mockReturnValue(); - mockDRepIdMismatch.mockReset(); - mockDRepIdMismatch.mockReturnValue(); + mockDappError.mockReset(); + mockDappError.mockReturnValue(); mockUseTranslation.mockReset(); mockUseTranslation.mockImplementation(() => ({ t })); }); @@ -252,6 +252,6 @@ describe('Testing ConfirmDRepRetirementContainer component', () => { )); }); - expect(queryByTestId('DRepIdMismatch')).toBeInTheDocument(); + expect(queryByTestId('DappError')).toBeInTheDocument(); }); }); diff --git a/apps/browser-extension-wallet/src/features/dapp/components/index.ts b/apps/browser-extension-wallet/src/features/dapp/components/index.ts index 4d3125556d..c96197a717 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/index.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/index.ts @@ -2,7 +2,6 @@ export * from './Connect'; export * from './SignTxFlowContainer'; export * from './DappTransactionSuccess'; export * from './DappTransactionFail'; -export * from './NoWallet'; export * from './ConfirmData'; export * from './BetaPill'; export * from './SignDataFlowContainer'; diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index 001454e8ee..4f53c319ed 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -328,7 +328,7 @@ "copyHandle": "Copy handle" }, "dapp": { - "nowallet.btn": "Create or restore a wallet", + "dappErrorPage.closeButton": "Cancel", "connect.header": "Authorize DApp", "connect.btn.accept": "Authorize", "connect.btn.cancel": "Cancel", @@ -367,6 +367,7 @@ "delete.confirm": "Disconnect DApp", "noWallet.heading": "You don't have a wallet right now", "noWallet.description": "You'll need to create or restore a wallet to connect to a dApp or make a transaction.", + "noWallet.closeButton": "Create or restore a wallet", "educationBanner.title": "DApp Guide", "betaModal": { "header": "DApp connector is now in Beta", diff --git a/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx b/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx index 753bf49e60..5553484572 100644 --- a/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx +++ b/apps/browser-extension-wallet/src/routes/DappConnectorView.tsx @@ -11,7 +11,6 @@ import { Connect as DappConnect, SignTxFlowContainer, SignDataFlowContainer, - NoWallet, DappTransactionSuccess, DappTransactionFail, DappCollateralContainer @@ -23,6 +22,9 @@ import { lockWalletSelector } from '@src/features/unlock-wallet/selectors'; import { useAppSettingsContext } from '@providers'; import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; +import { DappError } from '@src/features/dapp/components/DappError'; +import { tabs } from 'webextension-polyfill'; +import { useTranslation } from 'react-i18next'; dayjs.extend(duration); @@ -34,6 +36,7 @@ const isLastValidationExpired = (lastVerification: string, frequency: string): b // TODO: unify providers and logic to load wallet and such for popup, dapp and browser view in one place [LW-5341] export const DappConnectorView = (): React.ReactElement => { + const { t } = useTranslation(); const [{ lastMnemonicVerification, mnemonicVerificationFrequency }] = useAppSettingsContext(); const { inMemoryWallet, keyAgentData, currentChain, walletInfo, setKeyAgentData, initialHdDiscoveryCompleted } = useWalletStore(); @@ -76,7 +79,19 @@ export const DappConnectorView = (): React.ReactElement => { if (hasNoAvailableWallet) { return ( - + { + tabs.create({ url: 'app.html#/setup' }); + }} + containerTestId="no-wallet-container" + imageTestId="no-wallet-image" + titleTestId="no-wallet-heading" + descriptionTestId="no-wallet-description" + closeButtonTestId="create-or-restore-wallet-btn" + /> ); } From 857d956013c07be2de51dbe9eea6d995c0330828 Mon Sep 17 00:00:00 2001 From: "przemyslaw.wlodek" Date: Tue, 5 Dec 2023 18:23:43 +0100 Subject: [PATCH 9/9] test(extension): fix mock import path --- .../__tests__/ConfirmDRepRetirementContainer.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx index ce95751ae9..570bbdb16e 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/__tests__/ConfirmDRepRetirementContainer.test.tsx @@ -96,8 +96,8 @@ jest.mock('@lace/core', () => { }; }); -jest.mock('../DappError', () => { - const original = jest.requireActual('../DappError'); +jest.mock('../../DappError', () => { + const original = jest.requireActual('../../DappError'); return { __esModule: true, ...original,