1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-23 02:10:12 +01:00
metamask-extension/ui/components/app/permission-page-container/permission-page-container.component.js
Hassan Malik ff36e32fb0
[FLASK] Improve snaps connect flow (#19461)
* add todo comments

* add snaps-connect component

* added new messages

* added component scss files to main scss files

* remove dead code and add snap-connect-cell

* update snaps connect

* updated messages and styling

* update messages and css

* update css

* moved snaps privacy warning into snaps connect, moved snaps connect error into snap install

* added story and removed unused import

* fix style linting and move snaps connect error css

* removed unused message

* ran lavamoat policy generation

* fix fencing

* some more css changes

* Fix scrolling and box shadow

* added comment, fixed quote

* Align more with Figma

* Regen LavaMoat policies

* bring back privacy logic to permission page container

* Revert scrolling changes + fix snaps icon

* fix linting, reintroduced dedupe logic and additionally addressed a corner case

* made some fixes

* Fix scrolling with multiple snaps

* add dedupe logic to snaps connect and fix spacing issue

* policy regen

* lint fix

* fix fencing

* replaced with new icon design, trimmed origin urls in certain places

* remove unused imports

* badge icon size

* Revert LM policy changes

* Use SnapAvatar for snaps-connect

* Use InstallError for connection failed

* Delete unused CSS file

* Remove unused CSS

* Use useOriginMetadata

* addressed PR comments

* fix linting errors

* add explicit condition

* fix fencing

* fix some more fencing

* fix util fencing issue

* fix storybook file, prevent null destructuring

* Fix storybook origin URLs

* Fix wrong prop name

---------

Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
Co-authored-by: Guillaume Roux <guillaumeroux123@gmail.com>
Co-authored-by: Erik Nilsson <eriks@mail.se>
2023-06-09 10:36:38 -04:00

227 lines
6.5 KiB
JavaScript

import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { isEqual } from 'lodash';
///: BEGIN:ONLY_INCLUDE_IN(snaps)
import {
SnapCaveatType,
WALLET_SNAP_PERMISSION_KEY,
} from '@metamask/rpc-methods';
///: END:ONLY_INCLUDE_IN
import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics';
import { PageContainerFooter } from '../../ui/page-container';
import PermissionsConnectFooter from '../permissions-connect-footer';
///: BEGIN:ONLY_INCLUDE_IN(snaps)
import { RestrictedMethods } from '../../../../shared/constants/permissions';
import SnapPrivacyWarning from '../snaps/snap-privacy-warning';
import { getDedupedSnaps } from '../../../helpers/utils/util';
///: END:ONLY_INCLUDE_IN
import { PermissionPageContainerContent } from '.';
export default class PermissionPageContainer extends Component {
static propTypes = {
approvePermissionsRequest: PropTypes.func.isRequired,
rejectPermissionsRequest: PropTypes.func.isRequired,
selectedIdentities: PropTypes.array,
allIdentitiesSelected: PropTypes.bool,
///: BEGIN:ONLY_INCLUDE_IN(snaps)
currentPermissions: PropTypes.object,
snapsInstallPrivacyWarningShown: PropTypes.bool.isRequired,
setSnapsInstallPrivacyWarningShownStatus: PropTypes.func,
///: END:ONLY_INCLUDE_IN
request: PropTypes.object,
requestMetadata: PropTypes.object,
targetSubjectMetadata: PropTypes.shape({
name: PropTypes.string,
origin: PropTypes.string.isRequired,
subjectType: PropTypes.string.isRequired,
extensionId: PropTypes.string,
iconUrl: PropTypes.string,
}),
};
static defaultProps = {
request: {},
requestMetadata: {},
selectedIdentities: [],
allIdentitiesSelected: false,
///: BEGIN:ONLY_INCLUDE_IN(snaps)
currentPermissions: {},
///: END:ONLY_INCLUDE_IN
};
static contextTypes = {
t: PropTypes.func,
trackEvent: PropTypes.func,
};
state = {
selectedPermissions: this.getRequestedMethodState(
this.getRequestedMethodNames(this.props),
),
};
componentDidUpdate() {
const newMethodNames = this.getRequestedMethodNames(this.props);
if (!isEqual(Object.keys(this.state.selectedPermissions), newMethodNames)) {
// this should be a new request, so just overwrite
this.setState({
selectedPermissions: this.getRequestedMethodState(newMethodNames),
});
}
}
getRequestedMethodState(methodNames) {
return methodNames.reduce((acc, methodName) => {
///: BEGIN:ONLY_INCLUDE_IN(snaps)
if (methodName === RestrictedMethods.wallet_snap) {
acc[methodName] = this.getDedupedSnapPermissions();
return acc;
}
///: END:ONLY_INCLUDE_IN
acc[methodName] = true;
return acc;
}, {});
}
///: BEGIN:ONLY_INCLUDE_IN(snaps)
getDedupedSnapPermissions() {
const { request, currentPermissions } = this.props;
const snapKeys = getDedupedSnaps(request, currentPermissions);
const permission = request?.permissions?.[WALLET_SNAP_PERMISSION_KEY] || {};
return {
...permission,
caveats: [
{
type: SnapCaveatType.SnapIds,
value: snapKeys.reduce((caveatValue, snapId) => {
caveatValue[snapId] = {};
return caveatValue;
}, {}),
},
],
};
}
showSnapsPrivacyWarning() {
this.setState({
isShowingSnapsPrivacyWarning: true,
});
}
///: END:ONLY_INCLUDE_IN
getRequestedMethodNames(props) {
return Object.keys(props.request.permissions || {});
}
componentDidMount() {
this.context.trackEvent({
category: MetaMetricsEventCategory.Auth,
event: 'Tab Opened',
properties: {
action: 'Connect',
legacy_event: true,
},
});
///: BEGIN:ONLY_INCLUDE_IN(snaps)
if (this.props.request.permissions[WALLET_SNAP_PERMISSION_KEY]) {
if (this.props.snapsInstallPrivacyWarningShown === false) {
this.showSnapsPrivacyWarning();
}
}
///: END:ONLY_INCLUDE_IN
}
onCancel = () => {
const { request, rejectPermissionsRequest } = this.props;
rejectPermissionsRequest(request.metadata.id);
};
onSubmit = () => {
const {
request: _request,
approvePermissionsRequest,
rejectPermissionsRequest,
selectedIdentities,
} = this.props;
const request = {
..._request,
permissions: { ..._request.permissions },
approvedAccounts: selectedIdentities.map(
(selectedIdentity) => selectedIdentity.address,
),
};
Object.keys(this.state.selectedPermissions).forEach((key) => {
if (!this.state.selectedPermissions[key]) {
delete request.permissions[key];
}
});
if (Object.keys(request.permissions).length > 0) {
approvePermissionsRequest(request);
} else {
rejectPermissionsRequest(request.metadata.id);
}
};
render() {
const {
requestMetadata,
targetSubjectMetadata,
selectedIdentities,
allIdentitiesSelected,
} = this.props;
///: BEGIN:ONLY_INCLUDE_IN(snaps)
const setIsShowingSnapsPrivacyWarning = (value) => {
this.setState({
isShowingSnapsPrivacyWarning: value,
});
};
const confirmSnapsPrivacyWarning = () => {
setIsShowingSnapsPrivacyWarning(false);
this.props.setSnapsInstallPrivacyWarningShownStatus(true);
};
///: END:ONLY_INCLUDE_IN
return (
<div className="page-container permission-approval-container">
{
///: BEGIN:ONLY_INCLUDE_IN(snaps)
<>
{this.state.isShowingSnapsPrivacyWarning && (
<SnapPrivacyWarning
onAccepted={() => confirmSnapsPrivacyWarning()}
onCanceled={() => this.onCancel()}
/>
)}
</>
///: END:ONLY_INCLUDE_IN
}
<PermissionPageContainerContent
requestMetadata={requestMetadata}
subjectMetadata={targetSubjectMetadata}
selectedPermissions={this.state.selectedPermissions}
selectedIdentities={selectedIdentities}
allIdentitiesSelected={allIdentitiesSelected}
/>
<div className="permission-approval-container__footers">
<PermissionsConnectFooter />
<PageContainerFooter
cancelButtonType="default"
onCancel={() => this.onCancel()}
cancelText={this.context.t('cancel')}
onSubmit={() => this.onSubmit()}
submitText={this.context.t('connect')}
buttonSizeLarge={false}
/>
</div>
</div>
);
}
}