Skip to content

Commit

Permalink
feat: adding tooltip to signature decoding state changes (#28430)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Add tooltip to state change labels.

## **Related issues**

Fixes: MetaMask/MetaMask-planning#3628

## **Manual testing steps**

1. Enable signature decoding locally.
2. Check NFT bidding or listing permit
3. It should show appropriate tooltip

## **Screenshots/Recordings**
<img width="358" alt="Screenshot 2024-11-13 at 10 55 39 AM"
src="https://github.com/user-attachments/assets/69c165b2-268b-4d8a-b8c6-ed24aad0b693">

## **Pre-merge author checklist**

- [X] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I’ve included tests if applicable
- [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

---------

Co-authored-by: MetaMask Bot <metamaskbot@users.noreply.github.com>
  • Loading branch information
jpuri and metamaskbot authored Nov 25, 2024
1 parent ebb4926 commit 67b2f5a
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 19 deletions.
6 changes: 6 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import configureMockStore from 'redux-mock-store';
import {
DecodingData,
DecodingDataChangeType,
DecodingDataStateChanges,
} from '@metamask/signature-controller';

import { getMockTypedSignConfirmStateForRequest } from '../../../../../../../../../test/data/confirmations/helper';
import { renderWithConfirmContextProvider } from '../../../../../../../../../test/lib/confirmations/render-helpers';
import { permitSignatureMsg } from '../../../../../../../../../test/data/confirmations/typed_sign';
import PermitSimulation from './decoded-simulation';
import PermitSimulation, { getStateChangeToolip } from './decoded-simulation';

const decodingData: DecodingData = {
stateChanges: [
Expand All @@ -22,6 +23,42 @@ const decodingData: DecodingData = {
],
};

const decodingDataListing: DecodingDataStateChanges = [
{
assetType: 'NATIVE',
changeType: DecodingDataChangeType.Receive,
address: '',
amount: '900000000000000000',
contractAddress: '',
},
{
assetType: 'ERC721',
changeType: DecodingDataChangeType.Listing,
address: '',
amount: '',
contractAddress: '0xafd4896984CA60d2feF66136e57f958dCe9482d5',
tokenID: '2101',
},
];

const decodingDataBidding: DecodingDataStateChanges = [
{
assetType: 'ERC721',
changeType: DecodingDataChangeType.Receive,
address: '',
amount: '900000000000000000',
contractAddress: '',
},
{
assetType: 'Native',
changeType: DecodingDataChangeType.Bidding,
address: '',
amount: '',
contractAddress: '0xafd4896984CA60d2feF66136e57f958dCe9482d5',
tokenID: '2101',
},
];

describe('DecodedSimulation', () => {
it('renders component correctly', async () => {
const state = getMockTypedSignConfirmStateForRequest({
Expand All @@ -38,4 +75,24 @@ describe('DecodedSimulation', () => {

expect(container).toMatchSnapshot();
});

describe('getStateChangeToolip', () => {
it('return correct tooltip when permit is for listing NFT', async () => {
const tooltip = getStateChangeToolip(
decodingDataListing,
decodingDataListing?.[0],
(str: string) => str,
);
expect(tooltip).toBe('signature_decoding_list_nft_tooltip');
});
});

it('return correct tooltip when permit is for bidding NFT', async () => {
const tooltip = getStateChangeToolip(
decodingDataBidding,
decodingDataBidding?.[0],
(str: string) => str,
);
expect(tooltip).toBe('signature_decoding_bid_nft_tooltip');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import {
DecodingDataChangeType,
DecodingDataStateChange,
DecodingDataStateChanges,
} from '@metamask/signature-controller';
import { Hex } from '@metamask/utils';

Expand All @@ -11,8 +12,35 @@ import { useI18nContext } from '../../../../../../../../hooks/useI18nContext';
import { SignatureRequestType } from '../../../../../../types/confirm';
import { useConfirmContext } from '../../../../../../context/confirm';
import StaticSimulation from '../../../shared/static-simulation/static-simulation';
import NativeValueDisplay from '../native-value-display/native-value-display';
import TokenValueDisplay from '../value-display/value-display';
import NativeValueDisplay from '../native-value-display/native-value-display';

export const getStateChangeToolip = (
stateChangeList: DecodingDataStateChanges | null,
stateChange: DecodingDataStateChange,
t: ReturnType<typeof useI18nContext>,
): string | undefined => {
if (stateChange.changeType === DecodingDataChangeType.Receive) {
if (
stateChangeList?.some(
(change) =>
change.changeType === DecodingDataChangeType.Listing &&
change.assetType === TokenStandard.ERC721,
)
) {
return t('signature_decoding_list_nft_tooltip');
}
if (
stateChange.assetType === TokenStandard.ERC721 &&
stateChangeList?.some(
(change) => change.changeType === DecodingDataChangeType.Bidding,
)
) {
return t('signature_decoding_bid_nft_tooltip');
}
}
return undefined;
};

const getStateChangeLabelMap = (
t: ReturnType<typeof useI18nContext>,
Expand All @@ -28,17 +56,23 @@ const getStateChangeLabelMap = (
}[changeType]);

const StateChangeRow = ({
stateChangeList,
stateChange,
chainId,
}: {
stateChangeList: DecodingDataStateChanges | null;
stateChange: DecodingDataStateChange;
chainId: Hex;
}) => {
const t = useI18nContext();
const { assetType, changeType, amount, contractAddress, tokenID } =
stateChange;
const tooltip = getStateChangeToolip(stateChangeList, stateChange, t);
return (
<ConfirmInfoRow label={getStateChangeLabelMap(t, changeType)}>
<ConfirmInfoRow
label={getStateChangeLabelMap(t, changeType)}
tooltip={tooltip}
>
{(assetType === TokenStandard.ERC20 ||
assetType === TokenStandard.ERC721) && (
<TokenValueDisplay
Expand Down Expand Up @@ -70,7 +104,11 @@ const DecodedSimulation: React.FC<object> = () => {

const stateChangeFragment = (decodingData?.stateChanges ?? []).map(
(change: DecodingDataStateChange) => (
<StateChangeRow stateChange={change} chainId={chainId} />
<StateChangeRow
stateChangeList={decodingData?.stateChanges ?? []}
stateChange={change}
chainId={chainId}
/>
),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const PermitSimulation: React.FC<object> = () => {

if (
decodingData?.error ||
(decodingData === undefined && decodingLoading !== true)
(decodingData?.stateChanges === undefined && decodingLoading !== true)
) {
return <DefaultSimulation />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ import {
} from '../../../../../../../../components/component-library';
import Tooltip from '../../../../../../../../components/ui/tooltip';
import {
BackgroundColor,
BlockSize,
BorderRadius,
Display,
JustifyContent,
TextAlign,
TextColor,
} from '../../../../../../../../helpers/constants/design-system';
import Name from '../../../../../../../../components/app/name/name';
import { TokenDetailsERC20 } from '../../../../../../utils/token';
import { getAmountColors } from '../../../utils';

type PermitSimulationValueDisplayParams = {
/** ID of the associated chain. */
Expand Down Expand Up @@ -112,16 +111,7 @@ const PermitSimulationValueDisplay: React.FC<
return null;
}

let valueColor = TextColor.textDefault;
let valueBackgroundColor = BackgroundColor.backgroundAlternative;

if (credit) {
valueColor = TextColor.successDefault;
valueBackgroundColor = BackgroundColor.successMuted;
} else if (debit) {
valueColor = TextColor.errorDefault;
valueBackgroundColor = BackgroundColor.errorMuted;
}
const { color, backgroundColor } = getAmountColors(credit, debit);

return (
<Box marginLeft="auto" style={{ maxWidth: '100%' }}>
Expand All @@ -139,9 +129,9 @@ const PermitSimulationValueDisplay: React.FC<
>
<Text
data-testid="simulation-token-value"
backgroundColor={valueBackgroundColor}
backgroundColor={backgroundColor}
borderRadius={BorderRadius.XL}
color={valueColor}
color={color}
paddingInline={2}
style={{ paddingTop: '1px', paddingBottom: '1px' }}
textAlign={TextAlign.Center}
Expand Down

0 comments on commit 67b2f5a

Please sign in to comment.