Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions ui/components/app/name/name-details/name-display.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import { NameType } from '@metamask/name-controller';
import { useDispatch, useSelector } from 'react-redux';
import { useDisplayName } from '../../../../hooks/useDisplayName';
import { TrustSignalDisplayState } from '../../../../hooks/useTrustSignals';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import { shortenAddress } from '../../../../helpers/utils/util';
import { toChecksumHexAddress } from '../../../../../shared/modules/hexstring-utils';
import NameDisplay from './name-display';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: jest.fn(),
useSelector: jest.fn(),
}));

jest.mock('../../../../hooks/useDisplayName', () => ({
useDisplayName: jest.fn(),
}));

describe('NameDisplay', () => {
const useDispatchMock = jest.mocked(useDispatch);
const useSelectorMock = jest.mocked(useSelector);
const useDisplayNameMock = jest.mocked(useDisplayName);

beforeEach(() => {
jest.resetAllMocks();
useDispatchMock.mockReturnValue(jest.fn());
useSelectorMock.mockReturnValue(jest.fn());
});

it('should render', () => {
useDisplayNameMock.mockReturnValue({
name: null,
hasPetname: false,
displayState: TrustSignalDisplayState.Unknown,
isAccount: false,
});
const { getByText } = renderWithProvider(
<NameDisplay
value={'0xdeadbeef'}
type={NameType.ETHEREUM_ADDRESS}
variation={'0x5'}
/>,
);
expect(
getByText(shortenAddress(toChecksumHexAddress('0xdeadbeef'))),
).toBeInTheDocument();
});

it('should render name from useDisplayName if available', () => {
useDisplayNameMock.mockReturnValue({
name: 'DisplayName',
hasPetname: false,
displayState: TrustSignalDisplayState.Unknown,
isAccount: false,
});
const { getByText } = renderWithProvider(
<NameDisplay
value={'0xdeadbeef'}
type={NameType.ETHEREUM_ADDRESS}
variation={'0x5'}
/>,
);
expect(getByText('DisplayName')).toBeInTheDocument();
});

it('should render fallback name if name is not available', () => {
useDisplayNameMock.mockReturnValue({
name: null,
hasPetname: false,
displayState: TrustSignalDisplayState.Unknown,
isAccount: false,
});
const { getByText } = renderWithProvider(
<NameDisplay
value={'0xdeadbeef'}
type={NameType.ETHEREUM_ADDRESS}
variation={'0x5'}
fallbackName={'TEST'}
/>,
);
expect(getByText('TEST')).toBeInTheDocument();
});
});
12 changes: 9 additions & 3 deletions ui/components/app/name/name-details/name-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export type NameDisplayProps = {
variation: string;
handleClick?: () => void;
showFullName?: boolean;
/**
* The fallback value to display if the name is not found or cannot be resolved.
*/
fallbackName?: string;
};

const NameDisplay = memo(
Expand All @@ -28,6 +32,7 @@ const NameDisplay = memo(
variation,
handleClick,
showFullName = false,
fallbackName,
...props
}: NameDisplayProps) => {
const { name, image, icon, displayState, isAccount } = useDisplayName({
Expand Down Expand Up @@ -64,19 +69,20 @@ const NameDisplay = memo(
};

const renderName = () => {
if (!name) {
const nameWithFallbackValue = name || fallbackName;
if (!nameWithFallbackValue) {
return <FormattedName value={value} type={type} {...props} />;
}

if (showFullName) {
if (name && showFullName) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Fallback Name Display Issue

When showFullName is true, if name is null but fallbackName is present, the fallbackName displays in a shortened format. The logic for full name display currently checks only for name, causing fallbackName to be incorrectly shortened.

Fix in Cursor Fix in Web

return (
<Text className="name__name" variant={TextVariant.bodyMd} {...props}>
{name}
</Text>
);
}

return <ShortenedName name={name} {...props} />;
return <ShortenedName name={nameWithFallbackValue} {...props} />;
};

return (
Expand Down
5 changes: 5 additions & 0 deletions ui/components/app/name/name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export type NameProps = {
* Such as the chain ID if the `type` is an Ethereum address.
*/
variation: string;

/**
* The fallback value to display if the name is not found or cannot be resolved.
*/
fallbackName?: string;
};

const Name = memo(
Expand Down
6 changes: 6 additions & 0 deletions ui/hooks/subscription/useSubscriptionPricing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ describe('useSubscriptionPricing', () => {
expect(result.current.loading).toBe(true);
expect(result.current.error).toBeUndefined();
expect(result.current.subscriptionPricing).toBeDefined();
expect(result.current.selectedTokenPrice).toBeUndefined();
});
});

Expand Down Expand Up @@ -220,6 +221,11 @@ describe('useSubscriptionPricing', () => {
trialPeriodDays: 7,
minBillingCycles: 1,
});
expect(result.current.selectedTokenPrice).toEqual(
mockSubscriptionPricing?.paymentMethods?.find(
(paymentMethod) => paymentMethod.type === PAYMENT_TYPES.byCrypto,
)?.chains?.[0]?.tokens?.[0],
);
});

it('should return yearly plan when approval amount matches yearly', async () => {
Expand Down
2 changes: 1 addition & 1 deletion ui/hooks/subscription/useSubscriptionPricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,5 +285,5 @@ export const useShieldSubscriptionPricingFromTokenApproval = ({
pricingPlans,
]);

return { productPrice, pending };
return { productPrice, pending, selectedTokenPrice };
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ export const EstimatedChanges = ({
tokenAddress,
chainId,
productPrice,
tokenSymbol,
}: {
approvalAmount: string;
tokenAddress: Hex;
chainId: Hex;
productPrice?: ProductPrice;
tokenSymbol?: string;
}) => {
const t = useI18nContext();

Expand Down Expand Up @@ -50,6 +52,7 @@ export const EstimatedChanges = ({
type={NameType.ETHEREUM_ADDRESS}
preferContractSymbol
variation={chainId}
fallbackName={tokenSymbol}
/>
</Box>
</ConfirmInfoRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ const ShieldSubscriptionApproveInfo = () => {
.div(10 ** (decimals ?? 0))
.toFixed();

const { productPrice, pending: productPricePending } =
useShieldSubscriptionPricingFromTokenApproval({
transactionMeta,
decodedApprovalAmount,
});
const {
productPrice,
pending: productPricePending,
selectedTokenPrice,
} = useShieldSubscriptionPricingFromTokenApproval({
transactionMeta,
decodedApprovalAmount,
});

const { trialedProducts, loading: subscriptionsLoading } =
useUserSubscriptions();
Expand All @@ -64,6 +67,7 @@ const ShieldSubscriptionApproveInfo = () => {
tokenAddress={transactionMeta?.txParams?.to as Hex}
chainId={transactionMeta?.chainId}
productPrice={productPrice}
tokenSymbol={selectedTokenPrice?.symbol}
/>
<AccountDetails
accountAddress={transactionMeta?.txParams?.from as Hex}
Expand Down
Loading