Skip to content

Commit 03b0c9c

Browse files
committed
Add a settings dialog, with "dangerous mode" setting
1 parent 3b53299 commit 03b0c9c

File tree

10 files changed

+187
-0
lines changed

10 files changed

+187
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React, { useState } from 'react'
2+
import { SidebarButton } from '../Sidebar'
3+
import { Configure } from 'grommet-icons/icons'
4+
import { useTranslation } from 'react-i18next'
5+
import { SettingsDialog } from '../SettingsDialog'
6+
7+
export const SettingsButton = () => {
8+
const [layerVisibility, setLayerVisibility] = useState(false)
9+
const { t } = useTranslation()
10+
return (
11+
<>
12+
<SidebarButton
13+
icon={<Configure />}
14+
label={t('menu.settings', 'Settings')}
15+
onClick={() => {
16+
setLayerVisibility(true)
17+
}}
18+
/>
19+
{layerVisibility && <SettingsDialog closeHandler={() => setLayerVisibility(false)} />}
20+
</>
21+
)
22+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React, { useContext } from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
import { ResponsiveLayer } from '../ResponsiveLayer'
4+
import { Box, Button, Heading, Paragraph, RadioButtonGroup, ResponsiveContext } from 'grommet'
5+
import { useDispatch, useSelector } from 'react-redux'
6+
import { selectDangerousModeSetting } from './slice/selectors'
7+
import { Threats } from 'grommet-icons'
8+
import { settingsActions } from './slice'
9+
10+
interface SettingsDialogProps {
11+
closeHandler: () => void
12+
}
13+
14+
export const SettingsDialog = (props: SettingsDialogProps) => {
15+
const { t } = useTranslation()
16+
const size = useContext(ResponsiveContext)
17+
18+
const dispatch = useDispatch()
19+
const dangerousMode = useSelector(selectDangerousModeSetting)
20+
21+
return (
22+
<ResponsiveLayer
23+
onClickOutside={props.closeHandler}
24+
onEsc={props.closeHandler}
25+
animation="slide"
26+
background="background-front"
27+
modal
28+
>
29+
<Box pad={{ vertical: 'small' }} margin="medium" width={size === 'small' ? 'auto' : '700px'}>
30+
<Heading size="1" margin={{ vertical: 'small' }}>
31+
{t('settings.dialog.title', 'Wallet settings')}
32+
</Heading>
33+
<Paragraph fill>
34+
{t(
35+
'settings.dialog.description',
36+
'This is where you can configure the behavior of the Oasis Wallet.',
37+
)}
38+
</Paragraph>
39+
<Box
40+
gap="small"
41+
pad={{ vertical: 'medium', right: 'small' }}
42+
overflow={{ vertical: 'auto' }}
43+
height={{ max: '400px' }}
44+
>
45+
<Paragraph fill>
46+
<b>{t('dangerMode.title', 'Dangerous mode')}:</b>{' '}
47+
{t('dangerMode.description', 'should the wallet let the user shoot himself in the foot?')}
48+
</Paragraph>
49+
<RadioButtonGroup
50+
name="doc"
51+
options={[
52+
{
53+
value: false,
54+
label: t('dangerMode.off', 'Off - Refuse to execute nonsensical actions'),
55+
},
56+
{
57+
value: true,
58+
label: (
59+
<span>
60+
{t('dangerMode.on', "On - Allow executing nonsensical actions. Don't blame Oasis!")}{' '}
61+
<Threats size={'large'} />
62+
</span>
63+
),
64+
},
65+
]}
66+
value={dangerousMode}
67+
onChange={event => dispatch(settingsActions.setDangerousMode(event.target.value === 'true'))}
68+
/>
69+
</Box>
70+
<Box align="end" pad={{ top: 'medium' }}>
71+
<Button primary label={t('settings.dialog.close', 'Close')} onClick={props.closeHandler} />
72+
</Box>
73+
</Box>
74+
</ResponsiveLayer>
75+
)
76+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { PayloadAction } from '@reduxjs/toolkit'
2+
import { createSlice } from 'utils/@reduxjs/toolkit'
3+
4+
import { SettingsState } from './types'
5+
6+
export const initialState: SettingsState = {
7+
dangerousMode: false,
8+
}
9+
10+
const slice = createSlice({
11+
name: 'settings',
12+
initialState,
13+
reducers: {
14+
setDangerousMode(state, action: PayloadAction<boolean>) {
15+
state.dangerousMode = action.payload
16+
},
17+
},
18+
})
19+
20+
export const { actions: settingsActions } = slice
21+
22+
export default slice.reducer
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createSelector } from '@reduxjs/toolkit'
2+
3+
import { RootState } from 'types'
4+
import { initialState } from '.'
5+
import { useSelector } from 'react-redux'
6+
7+
const selectSlice = (state: RootState) => state.settings || initialState
8+
9+
export const selectDangerousModeSetting = createSelector([selectSlice], settings => settings.dangerousMode)
10+
11+
export const useDangerModeSetting = () => useSelector(selectDangerousModeSetting)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface SettingsState {
2+
dangerousMode: boolean
3+
}

src/app/components/Sidebar/__tests__/__snapshots__/index.test.tsx.snap

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,39 @@ exports[`<Navigation /> should match snapshot 1`] = `
680680
<div
681681
class="c6"
682682
/>
683+
<button
684+
aria-label="menu.settings"
685+
class="c13"
686+
type="button"
687+
>
688+
<div
689+
class="c14"
690+
>
691+
<svg
692+
aria-label="Configure"
693+
class="c10"
694+
viewBox="0 0 24 24"
695+
>
696+
<path
697+
d="M16 15c4.009-.065 7-3.033 7-7 0-3.012-.997-2.015-2-1-.991.98-3 3-3 3l-4-4s2.02-2.009 3-3c1.015-1.003 1.015-2-1-2-3.967 0-6.947 2.991-7 7 .042.976 0 3 0 3-1.885 1.897-4.34 4.353-6 6-2.932 2.944 1.056 6.932 4 4 1.65-1.662 4.113-4.125 6-6 0 0 2.024-.042 3 0z"
698+
fill="none"
699+
stroke="#000"
700+
stroke-width="2"
701+
/>
702+
</svg>
703+
<div
704+
class="c11"
705+
/>
706+
<span
707+
class="c5"
708+
>
709+
menu.settings
710+
</span>
711+
</div>
712+
</button>
713+
<div
714+
class="c6"
715+
/>
683716
<a
684717
aria-label="GitHub"
685718
href="https://github.com/oasisprotocol/oasis-wallet-web"

src/app/components/Sidebar/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { Language } from '../../../styles/theme/icons/language/Language'
2222
import { ThemeSwitcher } from '../ThemeSwitcher'
2323
import logotype from '../../../../public/logo192.png'
2424
import { languageLabels } from '../../../locales/i18n'
25+
import { SettingsButton } from '../SettingsButton'
2526

2627
const SidebarTooltip = (props: { children: React.ReactNode; isActive: boolean; label: string }) => {
2728
const size = useContext(ResponsiveContext)
@@ -211,6 +212,7 @@ const SidebarFooter = (props: SidebarFooterProps) => {
211212
</Menu>
212213
</Box>
213214
</SidebarTooltip>
215+
<SettingsButton />
214216
<SidebarButton
215217
icon={<Github />}
216218
label="GitHub"

src/locales/en/translation.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@
119119
"newMnemonic": "Generate a new mnemonic",
120120
"thisIsYourPhrase": "This is your mnemonic"
121121
},
122+
"dangerMode": {
123+
"description": "should the wallet let the user shoot himself in the foot?",
124+
"off": "Off - Refuse to execute nonsensical actions",
125+
"on": "On - Allow executing nonsensical actions. Don't blame Oasis!",
126+
"title": "Dangerous mode"
127+
},
122128
"delegations": {
123129
"activeDelegations": "Active delegations",
124130
"debondingDelegations": "Debonding delegations",
@@ -193,6 +199,7 @@
193199
"menu": {
194200
"closeWallet": "Close wallet",
195201
"home": "Home",
202+
"settings": "Settings",
196203
"stake": "Stake",
197204
"wallet": "Wallet"
198205
},
@@ -229,6 +236,13 @@
229236
"showPrivateKey": "Show private key"
230237
}
231238
},
239+
"settings": {
240+
"dialog": {
241+
"close": "Close",
242+
"description": "This is where you can configure the behavior of the Oasis Wallet.",
243+
"title": "Wallet settings"
244+
}
245+
},
232246
"theme": {
233247
"darkMode": "Dark mode",
234248
"lightMode": "Light mode"

src/store/reducers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import stakingReducer from 'app/state/staking'
1212
import transactionReducer from 'app/state/transaction'
1313
import walletReducer from 'app/state/wallet'
1414
import themeReducer from 'styles/theme/slice'
15+
import settingReducer from 'app/components/SettingsDialog/slice'
1516

1617
export function createReducer() {
1718
const rootReducer = combineReducers({
@@ -24,6 +25,7 @@ export function createReducer() {
2425
theme: themeReducer,
2526
transaction: transactionReducer,
2627
wallet: walletReducer,
28+
settings: settingReducer,
2729
})
2830

2931
return rootReducer

src/types/RootState.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TransactionState } from 'app/state/transaction/types'
88
import { ImportAccountsState } from 'app/state/importaccounts/types'
99
import { StakingState } from 'app/state/staking/types'
1010
import { FatalErrorState } from 'app/state/fatalerror/types'
11+
import { SettingsState } from '../app/components/SettingsDialog/slice/types'
1112
// [IMPORT NEW CONTAINERSTATE ABOVE] < Needed for generating containers seamlessly
1213

1314
export interface RootState {
@@ -20,6 +21,7 @@ export interface RootState {
2021
importAccounts: ImportAccountsState
2122
staking: StakingState
2223
fatalError: FatalErrorState
24+
settings: SettingsState
2325
// [INSERT NEW REDUCER KEY ABOVE] < Needed for generating containers seamlessly
2426
}
2527

0 commit comments

Comments
 (0)