Feat/add collectible manually (#12834)

* hook up add collectible manually flow

* address feedback
feature/default_network_editable
Alex Donesky 3 years ago committed by GitHub
parent 609f541b76
commit 5aa191fd2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      app/_locales/en/messages.json
  2. 10
      app/scripts/metamask-controller.js
  3. 2
      package.json
  4. 7
      ui/ducks/app/app.js
  5. 24
      ui/pages/add-collectible/add-collectible.component.js
  6. 37
      ui/pages/home/home.component.js
  7. 6
      ui/pages/home/home.container.js
  8. 4
      ui/selectors/selectors.js
  9. 2
      ui/store/actionConstants.js
  10. 44
      ui/store/actions.js
  11. 8
      yarn.lock

@ -1680,6 +1680,12 @@
"message": "Account $1",
"description": "Default name of next account to be created on create account screen"
},
"newCollectibleAddFailed": {
"message": "Collectible was not added because: $1"
},
"newCollectibleAddedMessage": {
"message": "Collectible was successfully added!"
},
"newContact": {
"message": "New Contact"
},

@ -183,7 +183,9 @@ export default class MetamaskController extends EventEmitter {
state: initState.TokensController,
});
this.assetsContractController = new AssetsContractController();
this.assetsContractController = new AssetsContractController({
provider: this.provider,
});
this.collectiblesController = new CollectiblesController({
onPreferencesStateChange: this.preferencesController.store.subscribe.bind(
@ -588,6 +590,7 @@ export default class MetamaskController extends EventEmitter {
console.error(error);
}
});
this.networkController.lookupNetwork();
this.messageManager = new MessageManager({
metricsEvent: this.metaMetricsController.trackEvent.bind(
@ -1046,6 +1049,11 @@ export default class MetamaskController extends EventEmitter {
collectiblesController,
),
addCollectibleVerifyOwnership: nodeify(
collectiblesController.addCollectibleVerifyOwnership,
collectiblesController,
),
removeAndIgnoreCollectible: nodeify(
collectiblesController.removeAndIgnoreCollectible,
collectiblesController,

@ -111,7 +111,7 @@
"@keystonehq/metamask-airgapped-keyring": "0.2.1",
"@material-ui/core": "^4.11.0",
"@metamask/contract-metadata": "^1.28.0",
"@metamask/controllers": "^20.0.0",
"@metamask/controllers": "^20.1.0",
"@metamask/eth-ledger-bridge-keyring": "^0.10.0",
"@metamask/eth-token-tracker": "^3.0.1",
"@metamask/etherscan-link": "^2.1.0",

@ -55,6 +55,7 @@ export default function reduceApp(state = {}, action) {
ledgerWebHidConnectedStatus: WEBHID_CONNECTED_STATUSES.UNKNOWN,
ledgerTransportStatus: TRANSPORT_STATES.NONE,
newNetworkAdded: '',
newCollectibleAddedMessage: '',
...state,
};
@ -290,6 +291,12 @@ export default function reduceApp(state = {}, action) {
newNetworkAdded: action.value,
};
case actionConstants.SET_NEW_COLLECTIBLE_ADDED_MESSAGE:
return {
...appState,
newCollectibleAddedMessage: action.value,
};
case actionConstants.LOADING_METHOD_DATA_STARTED:
return {
...appState,

@ -1,27 +1,43 @@
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { useI18nContext } from '../../hooks/useI18nContext';
import { DEFAULT_ROUTE } from '../../helpers/constants/routes';
import Box from '../../components/ui/box';
import TextField from '../../components/ui/text-field';
import PageContainer from '../../components/ui/page-container';
import {
addCollectibleVerifyOwnership,
setNewCollectibleAddedMessage,
} from '../../store/actions';
export default function AddCollectible() {
const t = useI18nContext();
const history = useHistory();
const dispatch = useDispatch();
const [address, setAddress] = useState('');
const [tokenId, setTokenId] = useState('');
const handleAddCollectible = async () => {
try {
await dispatch(addCollectibleVerifyOwnership(address, tokenId));
} catch (error) {
const { message } = error;
dispatch(setNewCollectibleAddedMessage(message));
history.push(DEFAULT_ROUTE);
return;
}
dispatch(setNewCollectibleAddedMessage('success'));
history.push(DEFAULT_ROUTE);
};
return (
<PageContainer
title={t('addNFT')}
onSubmit={() => {
console.log(
`Adding collectible with ID: ${tokenId} and address ${address}`,
);
history.push(DEFAULT_ROUTE);
handleAddCollectible();
}}
submitText={t('add')}
onCancel={() => {

@ -92,6 +92,8 @@ export default class Home extends PureComponent {
newNetworkAdded: PropTypes.string,
setNewNetworkAdded: PropTypes.func.isRequired,
isSigningQRHardwareTransaction: PropTypes.bool.isRequired,
newCollectibleAddedMessage: PropTypes.string,
setNewCollectibleAddedMessage: PropTypes.func.isRequired,
};
state = {
@ -225,9 +227,42 @@ export default class Home extends PureComponent {
infuraBlocked,
newNetworkAdded,
setNewNetworkAdded,
newCollectibleAddedMessage,
setNewCollectibleAddedMessage,
} = this.props;
return (
<MultipleNotifications>
{newCollectibleAddedMessage ? (
<ActionableMessage
type={newCollectibleAddedMessage === 'success' ? 'info' : 'warning'}
className="home__new-network-notification"
message={
<div className="home__new-network-notification-message">
{newCollectibleAddedMessage === 'success' ? (
<img
src="./images/check_circle.svg"
className="home__new-network-notification-message--image"
/>
) : null}
<Typography
variant={TYPOGRAPHY.H7}
fontWeight={FONT_WEIGHT.NORMAL}
>
{newCollectibleAddedMessage === 'success'
? t('newCollectibleAddedMessage')
: t('newCollectibleAddFailed', [
newCollectibleAddedMessage,
])}
</Typography>
<button
className="fas fa-times home__close"
title={t('close')}
onClick={() => setNewCollectibleAddedMessage('')}
/>
</div>
}
/>
) : null}
{newNetworkAdded ? (
<ActionableMessage
type="info"
@ -242,7 +277,7 @@ export default class Home extends PureComponent {
variant={TYPOGRAPHY.H7}
fontWeight={FONT_WEIGHT.NORMAL}
>
{this.context.t('newNetworkAdded', [newNetworkAdded])}
{t('newNetworkAdded', [newNetworkAdded])}
</Typography>
<button
className="fas fa-times home__close"

@ -18,6 +18,7 @@ import {
getNewNetworkAdded,
hasUnsignedQRHardwareTransaction,
hasUnsignedQRHardwareMessage,
getNewCollectibleAddedMessage,
} from '../../selectors';
import {
@ -32,6 +33,7 @@ import {
setRecoveryPhraseReminderHasBeenShown,
setRecoveryPhraseReminderLastShown,
setNewNetworkAdded,
setNewCollectibleAddedMessage,
} from '../../store/actions';
import { setThreeBoxLastUpdated, hideWhatsNewPopup } from '../../ducks/app/app';
import { getWeb3ShimUsageAlertEnabledness } from '../../ducks/metamask/metamask';
@ -122,6 +124,7 @@ const mapStateToProps = (state) => {
seedPhraseBackedUp,
newNetworkAdded: getNewNetworkAdded(state),
isSigningQRHardwareTransaction,
newCollectibleAddedMessage: getNewCollectibleAddedMessage(state),
};
};
@ -154,6 +157,9 @@ const mapDispatchToProps = (dispatch) => ({
setNewNetworkAdded: (newNetwork) => {
dispatch(setNewNetworkAdded(newNetwork));
},
setNewCollectibleAddedMessage: (message) => {
dispatch(setNewCollectibleAddedMessage(message));
},
});
export default compose(

@ -735,6 +735,10 @@ export function doesAddressRequireLedgerHidConnection(state, address) {
);
}
export function getNewCollectibleAddedMessage(state) {
return state.appState.newCollectibleAddedMessage;
}
/**
* To retrieve the name of the new Network added using add network form
* @param {*} state

@ -90,6 +90,8 @@ export const SET_FIRST_TIME_FLOW_TYPE = 'SET_FIRST_TIME_FLOW_TYPE';
export const SET_SELECTED_SETTINGS_RPC_URL = 'SET_SELECTED_SETTINGS_RPC_URL';
export const SET_NEW_NETWORK_ADDED = 'SET_NEW_NETWORK_ADDED';
export const SET_NEW_COLLECTIBLE_ADDED_MESSAGE =
'SET_NEW_COLLECTIBLE_ADDED_MESSAGE';
export const LOADING_METHOD_DATA_STARTED = 'LOADING_METHOD_DATA_STARTED';
export const LOADING_METHOD_DATA_FINISHED = 'LOADING_METHOD_DATA_FINISHED';

@ -1317,6 +1317,43 @@ export function addCollectible(address, tokenID, dontShowLoadingIndicator) {
};
}
export function addCollectibleVerifyOwnership(
address,
tokenID,
dontShowLoadingIndicator,
) {
return async (dispatch) => {
if (!address) {
throw new Error('MetaMask - Cannot add collectible without address');
}
if (!tokenID) {
throw new Error('MetaMask - Cannot add collectible without tokenID');
}
if (!dontShowLoadingIndicator) {
dispatch(showLoadingIndication());
}
try {
await promisifiedBackground.addCollectibleVerifyOwnership(
address,
tokenID,
);
} catch (error) {
if (
error.message.includes('This collectible is not owned by the user') ||
error.message.includes('Unable to verify ownership.')
) {
throw error;
} else {
log.error(error);
dispatch(displayWarning(error.message));
}
} finally {
await forceUpdateMetamaskState(dispatch);
dispatch(hideLoadingIndication());
}
};
}
export function removeAndIgnoreCollectible(
address,
tokenID,
@ -2552,6 +2589,13 @@ export function setNewNetworkAdded(newNetworkAdded) {
};
}
export function setNewCollectibleAddedMessage(newCollectibleAddedMessage) {
return {
type: actionConstants.SET_NEW_COLLECTIBLE_ADDED_MESSAGE,
value: newCollectibleAddedMessage,
};
}
export function setLastActiveTime() {
return (dispatch) => {
background.setLastActiveTime((err) => {

@ -2606,10 +2606,10 @@
resolved "https://registry.yarnpkg.com/@metamask/contract-metadata/-/contract-metadata-1.30.0.tgz#fa8e1b0c3e7aaa963986088f691fb553ffbe3904"
integrity sha512-b2usYW/ptQYnE6zhUmr4T+nvOAQJK5ABcpKudyQANpy4K099elpv4aN0WcrcOcwV99NHOdMzFP3ZuG0HoAyOBQ==
"@metamask/controllers@^20.0.0":
version "20.0.0"
resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-20.0.0.tgz#5c3fd293e1c8d3de964bbbfadbd73d637d83a1a8"
integrity sha512-H7ql719730+KCFRvAxWVKe3PvEabKgA9b+0+k4/nRA2Xvb7Pe3BlQ4lgt44wOFKDqdWyvwvH7mgNTAhDzBu4OA==
"@metamask/controllers@^20.1.0":
version "20.1.0"
resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-20.1.0.tgz#1d8386dc22d14f9fd9feb8b3cc8314d663587550"
integrity sha512-Z/7uLGXZWbCBbtCybR3jo1bx3mcvZRUSm1i43od4dnJoQo2+Veq4ePrFVgPKS3WtLIM/hzZuI7UTAQ9HNX9aew==
dependencies:
"@ethereumjs/common" "^2.3.1"
"@ethereumjs/tx" "^3.2.1"

Loading…
Cancel
Save