Consolidate connected account alerts (#8802)
* update connected accounts appearance * consolidate account alerts * UnconnectedAccountAlert: use ConnectedAccountsList * move switch account action out of menu in all views Co-authored-by: Mark Stacey <markjstacey@gmail.com>feature/default_network_editable
parent
3f8fa161ca
commit
4dfe4e7463
@ -1 +0,0 @@ |
|||||||
export { default } from './switch-to-connected-alert' |
|
@ -1,121 +0,0 @@ |
|||||||
import React, { useState } from 'react' |
|
||||||
import { useDispatch, useSelector } from 'react-redux' |
|
||||||
|
|
||||||
import { |
|
||||||
ALERT_STATE, |
|
||||||
switchToAccount, |
|
||||||
dismissAlert, |
|
||||||
dismissAndDisableAlert, |
|
||||||
getAlertState, |
|
||||||
} from '../../../../ducks/alerts/switch-to-connected' |
|
||||||
import { getPermittedIdentitiesForCurrentTab } from '../../../../selectors' |
|
||||||
import Popover from '../../../ui/popover' |
|
||||||
import Button from '../../../ui/button' |
|
||||||
import Dropdown from '../../../ui/dropdown' |
|
||||||
import Checkbox from '../../../ui/check-box' |
|
||||||
import Tooltip from '../../../ui/tooltip-v2' |
|
||||||
import { useI18nContext } from '../../../../hooks/useI18nContext' |
|
||||||
|
|
||||||
const { |
|
||||||
ERROR, |
|
||||||
LOADING, |
|
||||||
} = ALERT_STATE |
|
||||||
|
|
||||||
const SwitchToUnconnectedAccountAlert = () => { |
|
||||||
const t = useI18nContext() |
|
||||||
const dispatch = useDispatch() |
|
||||||
const alertState = useSelector(getAlertState) |
|
||||||
const connectedAccounts = useSelector(getPermittedIdentitiesForCurrentTab) |
|
||||||
const [accountToSwitchTo, setAccountToSwitchTo] = useState(connectedAccounts[0].address) |
|
||||||
const [dontShowThisAgain, setDontShowThisAgain] = useState(false) |
|
||||||
|
|
||||||
const onClose = async () => { |
|
||||||
return dontShowThisAgain |
|
||||||
? await dispatch(dismissAndDisableAlert()) |
|
||||||
: dispatch(dismissAlert()) |
|
||||||
} |
|
||||||
|
|
||||||
const options = connectedAccounts.map((account) => { |
|
||||||
return { name: account.name, value: account.address } |
|
||||||
}) |
|
||||||
|
|
||||||
return ( |
|
||||||
<Popover |
|
||||||
contentClassName="switch-to-connected-alert__content" |
|
||||||
footer={( |
|
||||||
<> |
|
||||||
{ |
|
||||||
alertState === ERROR |
|
||||||
? ( |
|
||||||
<div className="switch-to-connected-alert__error"> |
|
||||||
{ t('failureMessage') } |
|
||||||
</div> |
|
||||||
) |
|
||||||
: null |
|
||||||
} |
|
||||||
<div className="switch-to-connected-alert__footer-buttons"> |
|
||||||
<Button |
|
||||||
disabled={alertState === LOADING} |
|
||||||
onClick={onClose} |
|
||||||
type="secondary" |
|
||||||
> |
|
||||||
{ t('dismiss') } |
|
||||||
</Button> |
|
||||||
<Button |
|
||||||
disabled={alertState === LOADING || alertState === ERROR || dontShowThisAgain} |
|
||||||
onClick={() => dispatch(switchToAccount(accountToSwitchTo))} |
|
||||||
type="primary" |
|
||||||
> |
|
||||||
{ t('switchAccounts') } |
|
||||||
</Button> |
|
||||||
</div> |
|
||||||
</> |
|
||||||
)} |
|
||||||
footerClassName="switch-to-connected-alert__footer" |
|
||||||
onClose={onClose} |
|
||||||
subtitle={ |
|
||||||
connectedAccounts.length > 1 |
|
||||||
? t('switchToConnectedAlertMultipleAccountsDescription') |
|
||||||
: t('switchToConnectedAlertSingleAccountDescription', [connectedAccounts[0].name]) |
|
||||||
} |
|
||||||
title={t('notConnected')} |
|
||||||
> |
|
||||||
{ |
|
||||||
connectedAccounts.length > 1 |
|
||||||
? ( |
|
||||||
<Dropdown |
|
||||||
className="switch-to-connected-alert__dropdown" |
|
||||||
title="Switch to account" |
|
||||||
onChange={(address) => setAccountToSwitchTo(address)} |
|
||||||
options={options} |
|
||||||
selectedOption={accountToSwitchTo} |
|
||||||
/> |
|
||||||
) |
|
||||||
: null |
|
||||||
} |
|
||||||
<div className="switch-to-connected-alert__checkbox-wrapper"> |
|
||||||
<Checkbox |
|
||||||
id="switchToConnected_dontShowThisAgain" |
|
||||||
checked={dontShowThisAgain} |
|
||||||
className="switch-to-connected-alert__checkbox" |
|
||||||
onClick={() => setDontShowThisAgain((checked) => !checked)} |
|
||||||
/> |
|
||||||
<label |
|
||||||
className="switch-to-connected-alert__checkbox-label" |
|
||||||
htmlFor="switchToConnected_dontShowThisAgain" |
|
||||||
> |
|
||||||
{ t('dontShowThisAgain') } |
|
||||||
<Tooltip |
|
||||||
position="top" |
|
||||||
title={t('unconnectedAccountAlertDisableTooltip')} |
|
||||||
wrapperClassName="switch-to-connected-alert__checkbox-label-tooltip" |
|
||||||
> |
|
||||||
<i className="fa fa-info-circle" /> |
|
||||||
</Tooltip> |
|
||||||
</label> |
|
||||||
</div> |
|
||||||
</Popover> |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
export default SwitchToUnconnectedAccountAlert |
|
@ -1,66 +0,0 @@ |
|||||||
.switch-to-connected-alert { |
|
||||||
&__footer { |
|
||||||
flex-direction: column; |
|
||||||
|
|
||||||
:only-child { |
|
||||||
margin: 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
&__footer-buttons { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
|
|
||||||
button:first-child { |
|
||||||
margin-right: 24px; |
|
||||||
} |
|
||||||
|
|
||||||
button { |
|
||||||
font-size: 14px; |
|
||||||
line-height: 20px; |
|
||||||
padding: 8px; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
&__error { |
|
||||||
margin-bottom: 16px; |
|
||||||
padding: 16px; |
|
||||||
font-size: 14px; |
|
||||||
border: 1px solid #D73A49; |
|
||||||
background: #F8EAE8; |
|
||||||
border-radius: 3px; |
|
||||||
} |
|
||||||
|
|
||||||
&__content { |
|
||||||
align-items: center; |
|
||||||
padding: 0 24px 24px 24px; |
|
||||||
} |
|
||||||
|
|
||||||
&__dropdown { |
|
||||||
background-color: white; |
|
||||||
width: 100%; |
|
||||||
margin-bottom: 24px; |
|
||||||
} |
|
||||||
|
|
||||||
&__checkbox-wrapper { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
&__checkbox { |
|
||||||
margin-right: 8px; |
|
||||||
} |
|
||||||
|
|
||||||
&__checkbox-label { |
|
||||||
font-size: 14px; |
|
||||||
margin-top: auto; |
|
||||||
margin-bottom: auto; |
|
||||||
color: $Grey-500; |
|
||||||
display: flex; |
|
||||||
} |
|
||||||
|
|
||||||
&__checkbox-label-tooltip { |
|
||||||
margin-left: 8px; |
|
||||||
} |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
export { default } from './connected-accounts-list-permissions.component' |
|
@ -0,0 +1 @@ |
|||||||
|
export { default } from './connected-accounts-permissions.component' |
@ -0,0 +1,64 @@ |
|||||||
|
.connected-accounts-permissions { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
|
||||||
|
font-size: 12px; |
||||||
|
line-height: 17px; |
||||||
|
color: $Grey-500; |
||||||
|
|
||||||
|
strong { |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
p + p { |
||||||
|
padding-top: 8px; |
||||||
|
} |
||||||
|
|
||||||
|
&__header { |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
cursor: pointer; |
||||||
|
|
||||||
|
font-size: 14px; |
||||||
|
line-height: 20px; |
||||||
|
color: #24292E; |
||||||
|
|
||||||
|
button { |
||||||
|
font-size: 16px; |
||||||
|
line-height: 24px; |
||||||
|
|
||||||
|
background: none; |
||||||
|
padding: 0; |
||||||
|
margin-left: 8px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&__list { |
||||||
|
padding-top: 8px; |
||||||
|
} |
||||||
|
|
||||||
|
&__list-item { |
||||||
|
display: flex; |
||||||
|
|
||||||
|
i { |
||||||
|
display: block; |
||||||
|
padding-right: 8px; |
||||||
|
font-size: 18px; |
||||||
|
color: $Grey-800; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&__list-container { |
||||||
|
max-height: 0px; |
||||||
|
overflow: hidden; |
||||||
|
height: auto; |
||||||
|
transition: max-height 0.8s cubic-bezier(0.4, 0.0, 0.2, 1); |
||||||
|
|
||||||
|
&--expanded { |
||||||
|
// arbitrarily set hard coded value for effect to work |
||||||
|
max-height: 100px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,2 +1 @@ |
|||||||
export { default as switchToConnected } from './switch-to-connected' |
|
||||||
export { default as unconnectedAccount } from './unconnected-account' |
export { default as unconnectedAccount } from './unconnected-account' |
||||||
|
@ -1,111 +0,0 @@ |
|||||||
import { createSlice } from '@reduxjs/toolkit' |
|
||||||
import { captureException } from '@sentry/browser' |
|
||||||
|
|
||||||
import { ALERT_TYPES } from '../../../../app/scripts/controllers/alert' |
|
||||||
import * as actionConstants from '../../store/actionConstants' |
|
||||||
import { setAlertEnabledness, setSelectedAddress } from '../../store/actions' |
|
||||||
|
|
||||||
// Constants
|
|
||||||
|
|
||||||
export const ALERT_STATE = { |
|
||||||
CLOSED: 'CLOSED', |
|
||||||
ERROR: 'ERROR', |
|
||||||
LOADING: 'LOADING', |
|
||||||
OPEN: 'OPEN', |
|
||||||
} |
|
||||||
|
|
||||||
const name = ALERT_TYPES.switchToConnected |
|
||||||
|
|
||||||
const initialState = { |
|
||||||
state: ALERT_STATE.CLOSED, |
|
||||||
} |
|
||||||
|
|
||||||
// Slice (reducer plus auto-generated actions and action creators)
|
|
||||||
|
|
||||||
const slice = createSlice({ |
|
||||||
name, |
|
||||||
initialState, |
|
||||||
reducers: { |
|
||||||
disableAlertFailed: (state) => { |
|
||||||
state.state = ALERT_STATE.ERROR |
|
||||||
}, |
|
||||||
disableAlertRequested: (state) => { |
|
||||||
state.state = ALERT_STATE.LOADING |
|
||||||
}, |
|
||||||
disableAlertSucceeded: (state) => { |
|
||||||
state.state = ALERT_STATE.CLOSED |
|
||||||
}, |
|
||||||
dismissAlert: (state) => { |
|
||||||
state.state = ALERT_STATE.CLOSED |
|
||||||
}, |
|
||||||
switchAccountFailed: (state) => { |
|
||||||
state.state = ALERT_STATE.ERROR |
|
||||||
}, |
|
||||||
switchAccountRequested: (state) => { |
|
||||||
state.state = ALERT_STATE.LOADING |
|
||||||
}, |
|
||||||
switchAccountSucceeded: (state) => { |
|
||||||
state.state = ALERT_STATE.CLOSED |
|
||||||
}, |
|
||||||
}, |
|
||||||
extraReducers: { |
|
||||||
[actionConstants.SELECTED_ADDRESS_CHANGED]: (state) => { |
|
||||||
// close the alert if the account is switched while it's open
|
|
||||||
if (state.state === ALERT_STATE.OPEN) { |
|
||||||
state.state = ALERT_STATE.CLOSED |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
const { actions, reducer } = slice |
|
||||||
|
|
||||||
export default reducer |
|
||||||
|
|
||||||
// Selectors
|
|
||||||
|
|
||||||
export const getAlertState = (state) => state[name].state |
|
||||||
|
|
||||||
export const alertIsOpen = (state) => state[name].state !== ALERT_STATE.CLOSED |
|
||||||
|
|
||||||
// Actions / action-creators
|
|
||||||
|
|
||||||
const { |
|
||||||
disableAlertFailed, |
|
||||||
disableAlertRequested, |
|
||||||
disableAlertSucceeded, |
|
||||||
dismissAlert, |
|
||||||
switchAccountFailed, |
|
||||||
switchAccountRequested, |
|
||||||
switchAccountSucceeded, |
|
||||||
} = actions |
|
||||||
|
|
||||||
export { dismissAlert } |
|
||||||
|
|
||||||
export const dismissAndDisableAlert = () => { |
|
||||||
return async (dispatch) => { |
|
||||||
try { |
|
||||||
await dispatch(disableAlertRequested()) |
|
||||||
await dispatch(setAlertEnabledness(name, false)) |
|
||||||
await dispatch(disableAlertSucceeded()) |
|
||||||
} catch (error) { |
|
||||||
console.error(error) |
|
||||||
captureException(error) |
|
||||||
await dispatch(disableAlertFailed()) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
export const switchToAccount = (address) => { |
|
||||||
return async (dispatch) => { |
|
||||||
try { |
|
||||||
await dispatch(switchAccountRequested()) |
|
||||||
await dispatch(setSelectedAddress(address)) |
|
||||||
await dispatch(switchAccountSucceeded()) |
|
||||||
} catch (error) { |
|
||||||
console.error(error) |
|
||||||
captureException(error) |
|
||||||
await dispatch(switchAccountFailed()) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue