Skip to content

Commit

Permalink
updated final screen for editing flow
Browse files Browse the repository at this point in the history
  • Loading branch information
NidhiKJha committed Sep 4, 2024
1 parent 694b4ee commit 34e3b54
Show file tree
Hide file tree
Showing 22 changed files with 246 additions and 301 deletions.
20 changes: 14 additions & 6 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3148,10 +3148,9 @@ export default class MetamaskController extends EventEmitter {
this.permissionController.grantPermissionsIncremental.bind(
this.permissionController,
),
grantPermissions:
this.permissionController.grantPermissions.bind(
this.permissionController,
),
grantPermissions: this.permissionController.grantPermissions.bind(
this.permissionController,
),
getProviderConfig: () => this.networkController.state.providerConfig,
setSecurityAlertsEnabled:
preferencesController.setSecurityAlertsEnabled.bind(
Expand Down
2 changes: 0 additions & 2 deletions test/data/mock-send-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
"appState": {
"networkDropdownOpen": false,
"importNftsModal": { "open": false },
"showEditAccountsModalOpen": false,
"showEditNetworksModalOpen": false,
"showPermittedNetworkToastOpen": false,
"gasIsLoading": false,
"isLoading": false,
Expand Down
2 changes: 0 additions & 2 deletions test/data/mock-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
"importNftsModal": {
"open": false
},
"showEditAccountsModalOpen": false,
"showEditNetworksModalOpen": false,
"showPermittedNetworkToastOpen": false,
"gasIsLoading": false,
"isLoading": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import { MetaMetricsContext } from '../../../contexts/metametrics';
import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard';
import { MINUTE } from '../../../../shared/constants/time';
import { NotificationsTagCounter } from '../notifications-tag-counter';
import { CONNECTIONS } from '../../../helpers/constants/routes';
import { CONNECTIONS, REVIEW_PERMISSIONS } from '../../../helpers/constants/routes';
import { MultichainNetwork } from '../../../selectors/multichain';

type AppHeaderUnlockedContentProps = {
Expand Down Expand Up @@ -115,6 +115,9 @@ export const AppHeaderUnlockedContent = ({
};

const handleConnectionsRoute = () => {
if (process.env.CHAIN_PERMISSIONS) {
history.push(`${REVIEW_PERMISSIONS}/${encodeURIComponent(origin)}`);
}
history.push(`${CONNECTIONS}/${encodeURIComponent(origin)}`);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { EthAccountType, KeyringAccountType } from '@metamask/keyring-api';
import { renderWithProvider } from '../../../../test/jest/rendering';
import { EditAccountsModal } from '.';
import mockState from '../../../../test/data/mock-state.json';
import configureStore from '../../../store/store';
import { EthAccountType, KeyringAccountType } from '@metamask/keyring-api';
import { EditAccountsModal } from '.';

const render = (
props: {
Expand Down
114 changes: 40 additions & 74 deletions ui/components/multichain/edit-accounts-modal/edit-accounts-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { TextVariant } from '../../../helpers/constants/design-system';
import {
EthAccountType,
InternalAccount,
isEvmAccountType,
KeyringAccountType,
} from '@metamask/keyring-api';
import { useI18nContext } from '../../../hooks/useI18nContext';
import {
getInternalAccounts,
getNonTestNetworks,
getOrderedConnectedAccountsForConnectedDapp,
getOriginOfCurrentTab,
getPermissionSubjects,
getTestNetworks,
getUpdatedAndSortedAccounts,
} from '../../../selectors';
import {
Expand All @@ -17,84 +20,78 @@ import {
ModalContent,
ModalHeader,
Checkbox,
Text,
Box,
ModalFooter,
ButtonPrimary,
ButtonPrimarySize,
ButtonSecondary,
} from '../../component-library';
import { AccountListItem } from '..';
import {
EthAccountType,
InternalAccount,
isEvmAccountType,
KeyringAccountType,
} from '@metamask/keyring-api';
import { MergedInternalAccount } from '../../../selectors/selectors.types';
import { mergeAccounts } from '../account-list-menu/account-list-menu';
import {
addMorePermittedAccounts,
removePermissionsFor,
removePermittedAccount,
} from '../../../store/actions';

type SendPageYourAccountsProps = {
allowedAccountTypes?: KeyringAccountType[];
};
import { NonEmptyArray } from '@metamask/utils';
import { SubjectsType } from '../pages/connections/components/connections.types';

const defaultAllowedAccountTypes = [EthAccountType.Eoa, EthAccountType.Erc4337];

export const EditAccountsModal = ({
interface EditAccountsModalProps {
onClose: () => void;
onClick: () => void;
allowedAccountTypes?: KeyringAccountType[];
}

export const EditAccountsModal: React.FC<EditAccountsModalProps> = ({
onClose,
onClick,
allowedAccountTypes = defaultAllowedAccountTypes,
}: {
onClose: () => void;
allowedAccountTypes: SendPageYourAccountsProps;
}) => {
const t = useI18nContext();
const accounts = useSelector(getUpdatedAndSortedAccounts);
const internalAccounts = useSelector(getInternalAccounts);
const dispatch = useDispatch();

const mergedAccounts: MergedInternalAccount[] = useMemo(() => {
return mergeAccounts(accounts, internalAccounts).filter(
(account: InternalAccount) => allowedAccountTypes.includes(account.type),
);
}, [accounts, internalAccounts]);
}, [accounts, internalAccounts, allowedAccountTypes]);

const activeTabOrigin = useSelector(getOriginOfCurrentTab);
const subjects = useSelector(getPermissionSubjects);
const connectedAccounts = useSelector((state) =>
// We only consider EVM accounts
// Connections with non-EVM accounts (Bitcoin only for now) are used implicitly and handled by the Bitcoin Snap itself.
const connectedAccounts = useSelector((state: any) =>
getOrderedConnectedAccountsForConnectedDapp(state, activeTabOrigin).filter(
(account: InternalAccount) => isEvmAccountType(account.type),
),
);

const connectedAccountsAddresses = connectedAccounts.map(
(account: { address: any }) => account.address,
(account: InternalAccount) => account.address,
);
const [selectedAccounts, setSelectedAccounts] = useState(

const [selectedAccounts, setSelectedAccounts] = useState<string[]>(
connectedAccountsAddresses,
);

const handleAccountClick = (address: string) => {
const index = selectedAccounts.indexOf(address);
let newSelectedAccounts: string[] = [];
let newSelectedAccounts: string[];

if (index === -1) {
// If address is not already selected, add it to the selectedAccounts array
newSelectedAccounts = [...selectedAccounts, address];
} else {
// If address is already selected, remove it from the selectedAccounts array
newSelectedAccounts = selectedAccounts.filter(
(_item, idx) => idx !== index,
(account) => account !== address,
);
}
setSelectedAccounts(newSelectedAccounts);
};

const disconnectAllAccounts = () => {
const subject = (subjects as SubjectsType)[activeTabOrigin];

if (subject) {
const permissionMethodNames = Object.values(subject.permissions).map(
({ parentCapability }: { parentCapability: string }) =>
Expand All @@ -115,72 +112,43 @@ export const EditAccountsModal = ({
};

const managePermittedAccounts = (
selectedAccounts,
connectedAccountsAddresses,
activeTabOrigin,
selectedAccounts: string[],
connectedAccountsAddresses: string[],
activeTabOrigin: string,
) => {
// Check if inputs are arrays; if not, set them to empty arrays
if (!Array.isArray(selectedAccounts)) {
console.error('selectedAccounts is not an array:', selectedAccounts);
selectedAccounts = [];
}

if (!Array.isArray(connectedAccountsAddresses)) {
console.error(
'connectedAccountsAddresses is not an array:',
connectedAccountsAddresses,
);
connectedAccountsAddresses = [];
}

// Find elements in connectedAccountsAddresses that are not in selectedAccounts
const removedElements = connectedAccountsAddresses.filter(
(account) => !selectedAccounts.includes(account),
);

if (removedElements.length > 0) {
// Dispatch removePermittedAccounts for each removed element
removedElements.forEach((account) => {
dispatch(removePermittedAccount(activeTabOrigin, account));
});
}

// Find new elements in selectedAccounts that are not in connectedAccountsAddresses
const newElements = selectedAccounts.filter(
(account) => !connectedAccountsAddresses.includes(account),
);

// Dispatch addMorePermittedAccounts for new elements
dispatch(addMorePermittedAccounts(activeTabOrigin, newElements));
if (newElements.length > 0) {
dispatch(addMorePermittedAccounts(activeTabOrigin, newElements));
}
};

return (
<Modal
isOpen
onClose={() => {
onClose();
}}
onClose={onClose}
data-testid="edit-accounts-modal"
className="edit-accounts-modal"
>
<ModalOverlay />
<ModalContent>
<ModalHeader
onClose={() => {
onClose();
}}
>
{t('editAccounts')}
</ModalHeader>
<ModalHeader onClose={onClose}>{t('editAccounts')}</ModalHeader>
<Box padding={4}>
<Checkbox
label={t('selectAll')}
isChecked
gap={4}
// onClick={() => (allAreSelected() ? deselectAll() : selectAll())}
// isIndeterminate={isIndeterminate}
/>
<Checkbox label={t('selectAll')} isChecked gap={4} />
</Box>
{mergedAccounts.map((account: any) => (
{mergedAccounts.map((account) => (
<AccountListItem
onClick={() => handleAccountClick(account.address)}
account={account}
Expand All @@ -189,9 +157,9 @@ export const EditAccountsModal = ({
startAccessory={
<Checkbox
isChecked={selectedAccounts.includes(account.address)}
// onClick={() => (allAreSelected() ? deselectAll() : selectAll())}
/>
}
selected={false}
/>
))}

Expand All @@ -213,6 +181,7 @@ export const EditAccountsModal = ({
<ButtonPrimary
data-testid="connect-more-accounts-button"
onClick={() => {
onClick();
managePermittedAccounts(
selectedAccounts,
connectedAccountsAddresses,
Expand All @@ -231,6 +200,3 @@ export const EditAccountsModal = ({
</Modal>
);
};

// if unchecked and connected then remove the account from connected list
// if checked and new update the connected accounts array
2 changes: 1 addition & 1 deletion ui/components/multichain/edit-accounts-modal/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { EditAccountsModal } from './edit-accounts-modal';
export { EditAccountsModal } from './edit-accounts-modal';
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
removePermittedChain,
} from '../../../store/actions';

export const EditNetworksModal = ({ onClose }) => {
export const EditNetworksModal = ({ onClose, onClick }) => {
const t = useI18nContext();
const dispatch = useDispatch();
const nonTestNetworks = useSelector(getNonTestNetworks);
Expand Down Expand Up @@ -148,12 +148,13 @@ export const EditNetworksModal = ({ onClose }) => {
<ButtonPrimary
data-testid="connect-more-accounts-button"
onClick={() => {
onClick();
onClose();
managePermittedChains(
selectedChains,
flattenedPermittedChains,
activeTabOrigin,
);
onClose();
); // Then call the managePermittedChains function
}}
size={ButtonPrimarySize.Lg}
block
Expand All @@ -172,4 +173,8 @@ EditNetworksModal.propTypes = {
* Executes when the modal closes
*/
onClose: PropTypes.func.isRequired,
/**
* Executes when the permissions are updated to show the toggle
*/
onClick: PropTypes.func.isRequired,
};
Loading

0 comments on commit 34e3b54

Please sign in to comment.