Skip to content

Commit

Permalink
[BX-1292] NFT Menus Refactor + Keyboard Shortcuts (#1334)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Sinclair <[email protected]>
  • Loading branch information
derHowie and DanielSinclair authored Feb 20, 2024
1 parent 1cbf41b commit 8cf0ab1
Show file tree
Hide file tree
Showing 10 changed files with 475 additions and 98 deletions.
130 changes: 130 additions & 0 deletions e2e/serial/send/3_nft-sendFlow.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import 'chromedriver';
import 'geckodriver';
import { WebDriver } from 'selenium-webdriver';
import { afterAll, afterEach, beforeAll, beforeEach, expect, it } from 'vitest';

import {
delayTime,
doNotFindElementByTestId,
findElementById,
findElementByIdAndClick,
findElementByTestId,
findElementByTestIdAndClick,
findElementByText,
findElementByTextAndClick,
getExtensionIdByName,
getRootUrl,
goToPopup,
importWalletFlow,
initDriverWithOptions,
querySelector,
shortenAddress,
takeScreenshotOnFailure,
transactionStatus,
waitAndClick,
} from '../../helpers';
import { TEST_VARIABLES } from '../../walletVariables';

let rootURL = getRootUrl();
let driver: WebDriver;

const browser = process.env.BROWSER || 'chrome';
const os = process.env.OS || 'mac';

beforeAll(async () => {
driver = await initDriverWithOptions({
browser,
os,
});
const extensionId = await getExtensionIdByName(driver, 'Rainbow');
if (!extensionId) throw new Error('Extension not found');
rootURL += extensionId;
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
beforeEach(async (context: any) => {
context.driver = driver;
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
afterEach(async (context: any) => {
await takeScreenshotOnFailure(context);
});

afterAll(() => driver.quit());

it('should be able import a wallet via pk', async () => {
await importWalletFlow(driver, rootURL, TEST_VARIABLES.SEED_WALLET.PK);
});

it('should be able import a second wallet via pk then switch back to wallet 1', async () => {
await importWalletFlow(
driver,
rootURL,
TEST_VARIABLES.PRIVATE_KEY_WALLET.SECRET,
true,
);
await findElementByIdAndClick({ id: 'header-account-name-shuffle', driver });
await findElementByTestIdAndClick({ id: 'wallet-account-1', driver });
const accountName = await findElementById({
id: 'header-account-name-shuffle',
driver,
});
expect(await accountName.getText()).toBe(
shortenAddress(TEST_VARIABLES.SEED_WALLET.ADDRESS),
);
});

it('should be able to go to setings', async () => {
await goToPopup(driver, rootURL);
await findElementByTestIdAndClick({ id: 'home-page-header-right', driver });
await findElementByTestIdAndClick({ id: 'settings-link', driver });
});

it('should be able to connect to hardhat and go to send flow', async () => {
const btn = await querySelector(driver, '[data-testid="connect-to-hardhat"]');
await waitAndClick(btn, driver);
const button = await findElementByText(driver, 'Disconnect from Hardhat');
expect(button).toBeTruthy();
await findElementByTestIdAndClick({ id: 'navbar-button-with-back', driver });
});

it('should be able to filter nfts and make selection on send flow', async () => {
await findElementByTestIdAndClick({ id: 'bottom-tab-nfts', driver });
await delayTime('very-long');
await delayTime('very-long');
await findElementByTestIdAndClick({ id: 'header-link-send', driver });
const input = await findElementByTestId({ id: 'to-address-input', driver });
await input.sendKeys('rainbowwallet.eth');

await findElementByTestIdAndClick({
id: 'input-wrapper-dropdown-token-input',
driver,
});
const assetInput = await findElementByTestId({ id: 'token-input', driver });
await assetInput.click();
await assetInput.sendKeys('uni');
const uniswapV3PositionsSection = await findElementByTestId({
id: 'nfts-collection-section-Uniswap V3 Positions',
driver,
});
const learnWeb3Badges = await doNotFindElementByTestId({
id: 'nfts-collection-section-LearnWeb3 Badges',
driver,
});
expect(uniswapV3PositionsSection).toBeTruthy();
expect(learnWeb3Badges).toBeFalsy();

await uniswapV3PositionsSection.click();
await findElementByTextAndClick(driver, '#521552');
});

it('should be able to go to review on send flow', async () => {
await findElementByTestIdAndClick({ id: 'send-review-button', driver });
});

it('should be able to send transaction on review on send flow', async () => {
await findElementByTestIdAndClick({ id: 'review-confirm-button', driver });
const sendTransaction = await transactionStatus();
expect(await sendTransaction).toBe('success');
});
16 changes: 16 additions & 0 deletions src/core/references/shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,22 @@ export const shortcuts = {
display: 'R',
key: 'r',
},
DOWNLOAD_NFT: {
display: 'D',
key: 'd',
},
COPY_NFT_ID: {
display: 'C',
key: 'c',
},
SEND_NFT: {
display: 'S',
key: 's',
},
HIDE_NFT: {
display: 'H',
key: 'h',
},
},
wallets: {
CHOOSE_WALLET_GROUP_NEW: {
Expand Down
15 changes: 10 additions & 5 deletions src/entries/popup/hooks/useHomeShortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useCurrentHomeSheetStore } from '~/core/state/currentHomeSheet';
import { useDeveloperToolsEnabledStore } from '~/core/state/currentSettings/developerToolsEnabled';
import { useFeatureFlagsStore } from '~/core/state/currentSettings/featureFlags';
import { useTestnetModeStore } from '~/core/state/currentSettings/testnetMode';
import { useSelectedNftStore } from '~/core/state/selectedNft';
import { useSelectedTokenStore } from '~/core/state/selectedToken';
import { useSelectedTransactionStore } from '~/core/state/selectedTransaction';
import { truncateAddress } from '~/core/utils/address';
Expand Down Expand Up @@ -52,6 +53,7 @@ export function useHomeShortcuts() {
const { isWatchingWallet } = useWallets();
const { testnetMode, setTestnetMode } = useTestnetModeStore();
const { developerToolsEnabled } = useDeveloperToolsEnabledStore();
const { selectedNft } = useSelectedNftStore();

const allowSend = useMemo(
() => !isWatchingWallet || featureFlags.full_watching_wallets,
Expand Down Expand Up @@ -112,11 +114,13 @@ export function useHomeShortcuts() {
navigate(ROUTES.BUY);
break;
case shortcuts.home.COPY_ADDRESS.key:
trackShortcut({
key: shortcuts.home.COPY_ADDRESS.display,
type: 'home.copyAddress',
});
handleCopy();
if (!selectedNft) {
trackShortcut({
key: shortcuts.home.COPY_ADDRESS.display,
type: 'home.copyAddress',
});
handleCopy();
}
break;
case shortcuts.home.GO_TO_CONNECTED_APPS.key:
trackShortcut({
Expand Down Expand Up @@ -228,6 +232,7 @@ export function useHomeShortcuts() {
handleTestnetMode,
alertWatchingWallet,
disconnectFromApp,
selectedNft,
],
);
useKeyboardShortcut({
Expand Down
4 changes: 4 additions & 0 deletions src/entries/popup/hooks/useKeyboardAnalytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export type KeyboardEventDescription =
| 'navbar.goBack'
| 'navigate.down'
| 'navigate.up'
| 'nfts.copyId'
| 'nfts.download'
| 'nfts.hide'
| 'nfts.send'
| 'radix.switchMenu.dismiss'
| 'send.cancel'
| 'send.copyContactAddress'
Expand Down
94 changes: 94 additions & 0 deletions src/entries/popup/hooks/useNftShortcuts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useCallback, useRef } from 'react';

import { i18n } from '~/core/languages';
import { shortcuts } from '~/core/references/shortcuts';
import { useCurrentAddressStore } from '~/core/state';
import { useNftsStore } from '~/core/state/nfts';
import { useSelectedNftStore } from '~/core/state/selectedNft';
import { UniqueAsset } from '~/core/types/nfts';

import { triggerToast } from '../components/Toast/Toast';
import { ROUTES } from '../urls';

import useKeyboardAnalytics from './useKeyboardAnalytics';
import { useKeyboardShortcut } from './useKeyboardShortcut';
import { useRainbowNavigate } from './useRainbowNavigate';

export function useNftShortcuts(nft?: UniqueAsset | null) {
const { currentAddress: address } = useCurrentAddressStore();
const { selectedNft, setSelectedNft } = useSelectedNftStore();
const { trackShortcut } = useKeyboardAnalytics();
const { toggleHideNFT } = useNftsStore();
const navigate = useRainbowNavigate();
const nftToFocus = nft ?? selectedNft;
const getNftIsSelected = useCallback(() => !!nftToFocus, [nftToFocus]);
const downloadLink = useRef<HTMLAnchorElement>(null);

const handleCopyId = useCallback(() => {
if (nftToFocus) {
navigator.clipboard.writeText(nftToFocus.id);
triggerToast({
title: i18n.t('nfts.details.copy_token_id'),
description: nftToFocus.id,
});
}
}, [nftToFocus]);

const handleDownload = useCallback(() => {
downloadLink.current?.click();
const link = document.createElement('a');
link.setAttribute('download', '');
link.href = nftToFocus?.image_url || '';
link.click();
link.remove();
}, [nftToFocus?.image_url]);

const handleHideNft = useCallback(() => {
toggleHideNFT(address, nftToFocus?.uniqueId || '');
}, [address, nftToFocus?.uniqueId, toggleHideNFT]);

const handleSendNft = useCallback(() => {
if (nft) {
setSelectedNft(nft);
navigate(ROUTES.SEND, { replace: true });
}
}, [navigate, nft, setSelectedNft]);

const handleNftShortcuts = useCallback(
(e: KeyboardEvent) => {
if (e.key === shortcuts.nfts.DOWNLOAD_NFT.key) {
handleDownload();
trackShortcut({
key: shortcuts.nfts.DOWNLOAD_NFT.display,
type: 'nfts.download',
});
}
if (e.key === shortcuts.nfts.COPY_NFT_ID.key) {
handleCopyId();
trackShortcut({
key: shortcuts.nfts.COPY_NFT_ID.display,
type: 'nfts.copyId',
});
}
if (e.key === shortcuts.nfts.HIDE_NFT.key) {
handleHideNft();
trackShortcut({
key: shortcuts.nfts.HIDE_NFT.display,
type: 'nfts.hide',
});
}
if (e.key === shortcuts.nfts.SEND_NFT.key) {
handleSendNft();
trackShortcut({
key: shortcuts.nfts.SEND_NFT.display,
type: 'nfts.send',
});
}
},
[handleCopyId, handleDownload, handleHideNft, handleSendNft, trackShortcut],
);
useKeyboardShortcut({
condition: getNftIsSelected,
handler: handleNftShortcuts,
});
}
Loading

0 comments on commit 8cf0ab1

Please sign in to comment.