diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 2965348a569..331754de1be 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -63,6 +63,7 @@ import AccountConnect from '../../../components/Views/AccountConnect'; import AccountPermissions from '../../../components/Views/AccountPermissions'; import { AccountPermissionsScreens } from '../../../components/Views/AccountPermissions/AccountPermissions.types'; import AccountPermissionsConfirmRevokeAll from '../../../components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll'; +import ConnectionDetails from '../../../components/Views/AccountPermissions/ConnectionDetails'; import { SRPQuiz } from '../../Views/Quiz'; import { TurnOffRememberMeModal } from '../../../components/UI/TurnOffRememberMeModal'; import AssetHideConfirmation from '../../Views/AssetHideConfirmation'; @@ -424,6 +425,10 @@ const RootModalFlow = () => ( name={Routes.SHEET.REVOKE_ALL_ACCOUNT_PERMISSIONS} component={AccountPermissionsConfirmRevokeAll} /> + {renderTopIcon()} - + + {!isRenderedAsBottomSheet && ( + { + navigate(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.SHEET.CONNECTION_DETAILS, + params: { + hostInfo: { + metadata: { + origin: + currentPageInformation?.url && + new URL(currentPageInformation?.url).hostname, + }, + }, + connectionDateTime: new Date().getTime(), + }, + }); + }} + testID={SDKSelectorsIDs.CONNECTION_DETAILS_BUTTON} + /> + )} + ); } @@ -150,20 +178,24 @@ const PermissionsSummary = ({ ); + const onRevokeAllHandler = useCallback(async () => { + await Engine.context.PermissionController.revokeAllPermissions(hostname); + navigate('PermissionsManager'); + }, [hostname, navigate]); + const toggleRevokeAllPermissionsModal = useCallback(() => { navigate(Routes.MODAL.ROOT_MODAL_FLOW, { screen: Routes.SHEET.REVOKE_ALL_ACCOUNT_PERMISSIONS, params: { hostInfo: { metadata: { - origin: - currentPageInformation?.url && - new URL(currentPageInformation?.url).hostname, + origin: hostname, }, }, + onRevokeAll: !isRenderedAsBottomSheet && onRevokeAllHandler, }, }); - }, [navigate, currentPageInformation?.url]); + }, [navigate, isRenderedAsBottomSheet, onRevokeAllHandler, hostname]); const getAccountLabel = useCallback(() => { if (isAlreadyConnected) { @@ -346,10 +378,10 @@ const PermissionsSummary = ({ {!isAlreadyConnected || isNetworkSwitch ? strings('permissions.title_dapp_url_wants_to', { - dappUrl: new URL(currentPageInformation.url).hostname, + dappUrl: hostname, }) : strings('permissions.title_dapp_url_has_approval_to', { - dappUrl: new URL(currentPageInformation.url).hostname, + dappUrl: hostname, })} diff --git a/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap b/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap index 5fb871e2b3d..dc178c8b497 100644 --- a/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap +++ b/app/components/UI/PermissionsSummary/__snapshots__/PermissionsSummary.test.tsx.snap @@ -99,6 +99,7 @@ exports[`PermissionsSummary should render correctly 1`] = ` { >([]); const { toastRef } = useContext(ToastContext); - const accountAvatarType = useSelector((state: RootState) => - state.settings.useBlockieIcon - ? AvatarAccountType.Blockies - : AvatarAccountType.JazzIcon, - ); // origin is set to the last active tab url in the browser which can conflict with sdk const inappBrowserOrigin: string = useSelector(getActiveTabUrl, isEqual); @@ -439,11 +432,6 @@ const AccountConnect = (props: AccountConnectProps) => { }; const connectedAccountLength = selectedAddresses.length; const activeAddress = selectedAddresses[0]; - const activeAccountName = getAccountNameWithENS({ - accountAddress: activeAddress, - accounts, - ensByAccountAddress, - }); try { setIsLoading(true); @@ -463,26 +451,15 @@ const AccountConnect = (props: AccountConnectProps) => { source: eventSource, }); let labelOptions: ToastOptions['labelOptions'] = []; - if (connectedAccountLength > 1) { - labelOptions = [ - { label: `${connectedAccountLength} `, isBold: true }, - { - label: `${strings('toast.accounts_connected')}`, - }, - { label: `\n${activeAccountName} `, isBold: true }, - { label: strings('toast.now_active') }, - ]; - } else { - labelOptions = [ - { label: `${activeAccountName} `, isBold: true }, - { label: strings('toast.connected_and_active') }, - ]; + + if (connectedAccountLength >= 1) { + labelOptions = [{ label: `${strings('toast.permissions_updated')}` }]; } + toastRef?.current?.showToast({ - variant: ToastVariants.Account, + variant: ToastVariants.Network, labelOptions, - accountAddress: activeAddress, - accountAvatarType, + networkImageSource: faviconSource, hasNoTimeout: false, }); } catch (e) { @@ -496,14 +473,12 @@ const AccountConnect = (props: AccountConnectProps) => { eventSource, selectedAddresses, hostInfo, - accounts, - ensByAccountAddress, - accountAvatarType, toastRef, accountsLength, channelIdOrHostname, triggerDappViewedEvent, trackEvent, + faviconSource, ]); const handleCreateAccount = useCallback( diff --git a/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx b/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx index 157534a5c53..3dc556a5f01 100644 --- a/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx +++ b/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx @@ -21,6 +21,7 @@ import AccountSelectorList from '../../../UI/AccountSelectorList'; import HelpText, { HelpTextSeverity, } from '../../../../component-library/components/Form/HelpText'; +import Engine from '../../../../core/Engine'; // Internal dependencies. import { ConnectAccountBottomSheetSelectorsIDs } from '../../../../../e2e/selectors/Browser/ConnectAccountBottomSheet.selectors'; @@ -84,6 +85,11 @@ const AccountConnectMultiSelector = ({ [accounts, selectedAddresses, onSelectAddress], ); + const onRevokeAllHandler = useCallback(async () => { + await Engine.context.PermissionController.revokeAllPermissions(hostname); + navigate('PermissionsManager'); + }, [hostname, navigate]); + const toggleRevokeAllAccountPermissionsModal = useCallback(() => { navigate(Routes.MODAL.ROOT_MODAL_FLOW, { screen: Routes.SHEET.REVOKE_ALL_ACCOUNT_PERMISSIONS, @@ -93,9 +99,10 @@ const AccountConnectMultiSelector = ({ origin: urlWithProtocol && new URL(urlWithProtocol).hostname, }, }, + onRevokeAll: !isRenderedAsBottomSheet && onRevokeAllHandler, }, }); - }, [navigate, urlWithProtocol]); + }, [navigate, urlWithProtocol, isRenderedAsBottomSheet, onRevokeAllHandler]); const renderSelectAllButton = useCallback( () => diff --git a/app/components/Views/AccountPermissions/AccountPermissions.tsx b/app/components/Views/AccountPermissions/AccountPermissions.tsx index ed6589becd9..42101ac25ef 100755 --- a/app/components/Views/AccountPermissions/AccountPermissions.tsx +++ b/app/components/Views/AccountPermissions/AccountPermissions.tsx @@ -196,8 +196,7 @@ const AccountPermissions = (props: AccountPermissionsProps) => { useEffect(() => { if ( previousPermittedAccounts.current === undefined && - permittedAccountsByHostname.length === 0 && - isRenderedAsBottomSheet + permittedAccountsByHostname.length === 0 ) { // TODO - Figure out better UX instead of auto dismissing. However, we cannot be in this state as long as accounts are not connected. hideSheet(); diff --git a/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/AccountPermissionsConfirmRevokeAll.tsx b/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/AccountPermissionsConfirmRevokeAll.tsx index fa06c49bbc6..8d3082a2ef7 100644 --- a/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/AccountPermissionsConfirmRevokeAll.tsx +++ b/app/components/Views/AccountPermissions/AccountPermissionsConfirmRevokeAll/AccountPermissionsConfirmRevokeAll.tsx @@ -26,6 +26,7 @@ interface AccountPermissionsConfirmRevokeAllProps { hostInfo: { metadata: { origin: string }; }; + onRevokeAll?: () => void; }; }; } @@ -37,6 +38,7 @@ const AccountPermissionsConfirmRevokeAll = ( hostInfo: { metadata: { origin: hostname }, }, + onRevokeAll, } = props.route.params; const { styles } = useStyles(styleSheet, {}); @@ -48,12 +50,18 @@ const AccountPermissionsConfirmRevokeAll = ( const revokeAllAccounts = useCallback(async () => { try { - await Engine.context.PermissionController.revokeAllPermissions(hostname); - sheetRef.current?.onCloseBottomSheet(); + if (onRevokeAll) { + onRevokeAll(); + } else { + await Engine.context.PermissionController.revokeAllPermissions( + hostname, + ); + sheetRef.current?.onCloseBottomSheet(); + } } catch (e) { Logger.log(`Failed to revoke all accounts for ${hostname}`, e); } - }, [hostname, Engine.context.PermissionController]); + }, [hostname, Engine.context.PermissionController, onRevokeAll]); const onCancel = () => { sheetRef.current?.onCloseBottomSheet(); diff --git a/app/components/Views/AccountPermissions/ConnectionDetails/ConnectionDetails.styles.ts b/app/components/Views/AccountPermissions/ConnectionDetails/ConnectionDetails.styles.ts new file mode 100644 index 00000000000..4cd67a1f432 --- /dev/null +++ b/app/components/Views/AccountPermissions/ConnectionDetails/ConnectionDetails.styles.ts @@ -0,0 +1,26 @@ +// Third party dependencies. +import { StyleSheet } from 'react-native'; + +/** + * Style sheet function for AccountConnectMultiSelector screen. + * @returns StyleSheet object. + */ +const styleSheet = () => + StyleSheet.create({ + container: { + paddingHorizontal: 16, + alignItems: 'center', + }, + descriptionContainer: { + marginBottom: 16, + }, + buttonsContainer: { + flexDirection: 'row', + gap: 16, + }, + button: { + flex: 1, + }, + }); + +export default styleSheet; diff --git a/app/components/Views/AccountPermissions/ConnectionDetails/ConnectionDetails.tsx b/app/components/Views/AccountPermissions/ConnectionDetails/ConnectionDetails.tsx new file mode 100644 index 00000000000..49463cd91de --- /dev/null +++ b/app/components/Views/AccountPermissions/ConnectionDetails/ConnectionDetails.tsx @@ -0,0 +1,76 @@ +// Third party dependencies +import React, { useRef } from 'react'; + +// External dependencies +import { View } from 'react-native'; +import BottomSheetHeader from '../../../../component-library/components/BottomSheets/BottomSheetHeader'; +import Button, { + ButtonVariants, + ButtonSize, +} from '../../../../component-library/components/Buttons/Button'; +import Text, { + TextVariant, +} from '../../../../component-library/components/Texts/Text'; +import { strings } from '../../../../../locales/i18n'; +import BottomSheet, { + BottomSheetRef, +} from '../../../../component-library/components/BottomSheets/BottomSheet'; +import { useStyles } from '../../../../component-library/hooks'; +import styleSheet from './ConnectionDetails.styles'; + +interface ConnectionDetailsProps { + route: { + params: { + connectionDateTime?: number; + }; + }; +} + +const AccountPermissionsConfirmRevokeAll = (props: ConnectionDetailsProps) => { + const { connectionDateTime = 123456789 } = props.route.params; + + const { styles } = useStyles(styleSheet, {}); + + const sheetRef = useRef(null); + + const onDismiss = () => { + sheetRef.current?.onCloseBottomSheet(); + }; + + const formatConnectionDate = (timestamp: number) => + new Date(timestamp).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric', + }); + + return ( + + + + + {strings('permissions.connection_details_title')} + + + + + {strings('permissions.connection_details_description', { + connectionDateTime: formatConnectionDate(connectionDateTime), + })} + + + +