1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-04 23:14:56 +01:00
metamask-extension/ui/components/app/detected-token/detected-token.js

178 lines
5.8 KiB
JavaScript
Raw Normal View History

import React, { useState, useContext } from 'react';
2022-05-09 19:47:06 +02:00
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import { chain } from 'lodash';
import {
addImportedTokens,
2022-05-09 19:47:06 +02:00
ignoreTokens,
setNewTokensImported,
} from '../../../store/actions';
import { getDetectedTokensInCurrentNetwork } from '../../../selectors';
import { MetaMetricsContext } from '../../../contexts/metametrics';
2022-05-09 19:47:06 +02:00
import {
ASSET_TYPES,
TOKEN_STANDARDS,
} from '../../../../shared/constants/transaction';
import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics';
2022-05-09 19:47:06 +02:00
import DetectedTokenSelectionPopover from './detected-token-selection-popover/detected-token-selection-popover';
import DetectedTokenIgnoredPopover from './detected-token-ignored-popover/detected-token-ignored-popover';
const sortingBasedOnTokenSelection = (tokensDetected) => {
return (
chain(tokensDetected)
// get the values
.values()
// create a new object with keys 'selected', 'deselected' and group the tokens
.groupBy((token) => (token.selected ? 'selected' : 'deselected'))
// ditch the 'selected' property and get just the tokens'
.mapValues((group) =>
group.map(({ token }) => {
const { address, symbol, decimals, aggregators } = token;
return { address, symbol, decimals, aggregators };
}),
)
2022-05-09 19:47:06 +02:00
// Exit the chain and get the underlying value, an object.
.value()
);
};
2022-05-09 19:47:06 +02:00
const DetectedToken = ({ setShowDetectedTokens }) => {
const dispatch = useDispatch();
const trackEvent = useContext(MetaMetricsContext);
2022-05-09 19:47:06 +02:00
const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork);
const [tokensListDetected, setTokensListDetected] = useState(() =>
detectedTokens.reduce((tokenObj, token) => {
tokenObj[token.address] = { token, selected: true };
return tokenObj;
}, {}),
);
2022-07-31 20:26:40 +02:00
const [showDetectedTokenIgnoredPopover, setShowDetectedTokenIgnoredPopover] =
useState(false);
const [partiallyIgnoreDetectedTokens, setPartiallyIgnoreDetectedTokens] =
useState(false);
2022-05-09 19:47:06 +02:00
const importSelectedTokens = async (selectedTokens) => {
selectedTokens.forEach((importedToken) => {
trackEvent({
event: EVENT_NAMES.TOKEN_ADDED,
category: EVENT.CATEGORIES.WALLET,
sensitiveProperties: {
token_symbol: importedToken.symbol,
token_contract_address: importedToken.address,
token_decimal_precision: importedToken.decimals,
source: EVENT.SOURCE.TOKEN.DETECTED,
token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN,
},
});
});
await dispatch(addImportedTokens(selectedTokens));
const tokenSymbols = selectedTokens.map(({ symbol }) => symbol);
dispatch(setNewTokensImported(tokenSymbols.join(', ')));
};
2022-05-09 19:47:06 +02:00
const handleClearTokensSelection = async () => {
2022-07-31 20:26:40 +02:00
const { selected: selectedTokens = [], deselected: deSelectedTokens = [] } =
sortingBasedOnTokenSelection(tokensListDetected);
2022-05-09 19:47:06 +02:00
if (deSelectedTokens.length < detectedTokens.length) {
await importSelectedTokens(selectedTokens);
2022-05-09 19:47:06 +02:00
}
const tokensDetailsList = deSelectedTokens.map(
({ symbol, address }) => `${symbol} - ${address}`,
);
trackEvent({
event: EVENT_NAMES.TOKEN_HIDDEN,
category: EVENT.CATEGORIES.WALLET,
sensitiveProperties: {
tokens: tokensDetailsList,
location: EVENT.LOCATION.TOKEN_DETECTION,
token_standard: TOKEN_STANDARDS.ERC20,
asset_type: ASSET_TYPES.TOKEN,
},
});
const deSelectedTokensAddresses = deSelectedTokens.map(
({ address }) => address,
);
await dispatch(
ignoreTokens({
tokensToIgnore: deSelectedTokensAddresses,
dontShowLoadingIndicator: true,
}),
);
2022-05-09 19:47:06 +02:00
setShowDetectedTokens(false);
setPartiallyIgnoreDetectedTokens(false);
2022-05-09 19:47:06 +02:00
};
const handleTokenSelection = (token) => {
setTokensListDetected((prevState) => ({
...prevState,
[token.address]: {
...prevState[token.address],
selected: !prevState[token.address].selected,
},
}));
};
const onImport = async () => {
2022-07-31 20:26:40 +02:00
const { selected: selectedTokens = [] } =
sortingBasedOnTokenSelection(tokensListDetected);
2022-05-09 19:47:06 +02:00
if (selectedTokens.length < detectedTokens.length) {
setShowDetectedTokenIgnoredPopover(true);
setPartiallyIgnoreDetectedTokens(true);
2022-05-09 19:47:06 +02:00
} else {
await importSelectedTokens(selectedTokens);
2022-05-09 19:47:06 +02:00
setShowDetectedTokens(false);
}
};
const onIgnoreAll = () => {
const newTokensListDetected = { ...tokensListDetected };
for (const tokenAddress of Object.keys(tokensListDetected)) {
newTokensListDetected[tokenAddress].selected = false;
}
setTokensListDetected(newTokensListDetected);
setShowDetectedTokenIgnoredPopover(true);
};
const onCancelIgnore = () => {
setShowDetectedTokenIgnoredPopover(false);
setPartiallyIgnoreDetectedTokens(false);
2022-05-09 19:47:06 +02:00
};
return (
<>
{showDetectedTokenIgnoredPopover && (
<DetectedTokenIgnoredPopover
onCancelIgnore={onCancelIgnore}
handleClearTokensSelection={handleClearTokensSelection}
partiallyIgnoreDetectedTokens={partiallyIgnoreDetectedTokens}
2022-05-09 19:47:06 +02:00
/>
)}
{detectedTokens.length > 0 && (
<DetectedTokenSelectionPopover
detectedTokens={detectedTokens}
tokensListDetected={tokensListDetected}
handleTokenSelection={handleTokenSelection}
onImport={onImport}
onIgnoreAll={onIgnoreAll}
setShowDetectedTokens={setShowDetectedTokens}
sortingBasedOnTokenSelection={sortingBasedOnTokenSelection}
/>
)}
2022-05-09 19:47:06 +02:00
</>
);
};
DetectedToken.propTypes = {
setShowDetectedTokens: PropTypes.func.isRequired,
};
export default DetectedToken;