Skip to content
This repository has been archived by the owner on Nov 7, 2023. It is now read-only.

Add logout button #54

Merged
merged 3 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/app/Authenticated/AuthenticatedComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@ interface AuthenticatedComponentInterface {
address: string | null
persona: DataVaultKey
modifyMultipleItems: (client: DataVaultWebClient, items: DataVaultKey) => any
logout: () => void
}

const AuthenticatedComponent: React.FC<AuthenticatedComponentInterface> = ({ chainId, address, persona, modifyMultipleItems }) => {
const AuthenticatedComponent: React.FC<AuthenticatedComponentInterface> = ({ chainId, address, persona, modifyMultipleItems, logout }) => {
const [screen, setScreen] = useState<screens>(screens.DASHBOARD)
const context = useContext(Web3ProviderContext)

const changeScreen = (screen: screens) => setScreen(screen)
const updatePersona = (items: DataVaultKey) => context.dvClient && modifyMultipleItems(context.dvClient, items)
const handleLogout = () => {
context.reset()
logout()
}

return (
<>
Expand All @@ -37,6 +42,7 @@ const AuthenticatedComponent: React.FC<AuthenticatedComponentInterface> = ({ cha
selected={screen}
handleClick={changeScreen}
showDataVault={!!context.dvClient}
logout={handleLogout}
/>
{screen === screens.DASHBOARD && <DashboardContainer changeScreen={changeScreen} />}
{screen === screens.DATAVAULT && <DataVaultContainer />}
Expand Down
4 changes: 3 additions & 1 deletion src/app/Authenticated/AuthenticatedContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { stateInterface } from '../state/configureStore'
import AuthenticatedComponent from './AuthenticatedComponent'
import { modifyMultipleItems } from '../state/operations/datavault'
import { DataVaultKey } from '../state/reducers/datavault'
import { logout } from '../state/operations/identity'

/**
* Get items that are specifically to the Persona from the DataVault collection
Expand All @@ -31,7 +32,8 @@ const mapStateToProps = (state: stateInterface) => ({

const mapDispatchToProps = (dispatch: ThunkDispatch<stateInterface, {}, AnyAction>) => ({
modifyMultipleItems: (client: DataVaultWebClient, items: DataVaultKey) =>
dispatch(modifyMultipleItems(client, items))
dispatch(modifyMultipleItems(client, items)),
logout: () => dispatch(logout())
})

export default connect(mapStateToProps, mapDispatchToProps)(AuthenticatedComponent)
19 changes: 16 additions & 3 deletions src/app/Authenticated/components/Navigation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,34 @@ import { shallow, mount } from 'enzyme'
import Navigation, { screens } from './Navigation'

describe('Screen: Dashboard', () => {
const sharedProps = {
selected: 'DASHBOARD',
handleClick: jest.fn(),
logout: jest.fn()
}
it('renders the component', () => {
const wrapper = shallow(<Navigation selected='DASHBOARD' handleClick={jest.fn()} />)
const wrapper = shallow(<Navigation {...sharedProps} selected='DASHBOARD' />)
expect(wrapper).toBeDefined()
})

it('sets the active item', () => {
const wrapper = mount(<Navigation selected={screens.DASHBOARD} handleClick={jest.fn()} />)
const wrapper = mount(<Navigation {...sharedProps} selected={screens.DASHBOARD} />)
expect(wrapper.find('li.active').text()).toBe('Dashboard')
})

it('function clicks the correct item', () => {
const onClick = jest.fn()
const wrapper = mount(<Navigation selected={screens.DASHBOARD} handleClick={onClick} showDataVault={true} />)
const wrapper = mount(<Navigation {...sharedProps} selected={screens.DASHBOARD} handleClick={onClick} showDataVault={true} />)

wrapper.find('.datavault').find('button').simulate('click')
expect(onClick).toBeCalledWith(screens.DATAVAULT)
})

it('calls logout when clicked', () => {
const logout = jest.fn()
const wrapper = shallow(<Navigation {...sharedProps} logout={logout} />)
wrapper.find('.logout').find('button').simulate('click')

expect(logout).toBeCalledTimes(1)
})
})
4 changes: 3 additions & 1 deletion src/app/Authenticated/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ interface NavigationInterface {
selected: string
handleClick: (screen: screens) => void
showDataVault?: boolean
logout: () => void
}

const Navigation: React.FC<NavigationInterface> = ({ selected, showDataVault, handleClick }) => (
const Navigation: React.FC<NavigationInterface> = ({ selected, showDataVault, handleClick, logout }) => (
<div className="container">
<div className="column">
<ul className="navigation">
Expand All @@ -34,6 +35,7 @@ const Navigation: React.FC<NavigationInterface> = ({ selected, showDataVault, ha
</li>
<li className="disabled">Request Credentials</li>
<li className="disabled">My Dapps</li>
<li className="logout"><button onClick={logout}>Logout</button></li>
</ul>
</div>
</div>
Expand Down
19 changes: 17 additions & 2 deletions src/app/state/operations/identity.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Dispatch } from 'react'

import { getAccountAndNetwork } from '../../../ethrpc'
import { rLogin } from '../../../features/rLogin'
import { rLogin, clearRloginStorage } from '../../../features/rLogin'

import { changeAccount, changeChainId } from '../reducers/identity'
import { changeAccount, changeChainId, reset as resetIdentity } from '../reducers/identity'
import { resolveDidDocument } from './ethrdid'
import { getBalance, getTokenList } from './defi'
import { dataVaultStart } from './datavault'

import { reset as resetDV } from '../reducers/datavault'
import { reset as resetDefi } from '../reducers/defi'
import { reset as resetEthrDid } from '../reducers/ethrdid'

/**
* Login into web3 provider via rLogin
* Saves the web3 provider into context and saves address and chainId to redux
Expand All @@ -30,3 +34,14 @@ export const login = (context: any) => (dispatch: Dispatch<any>) =>
})
})
.catch((err: string) => console.log('rLogin Error', err))

export const logout = () => (dispatch: Dispatch<any>) => {
// local storage
clearRloginStorage()

// reducers
dispatch(resetDV())
dispatch(resetDefi())
dispatch(resetEthrDid())
dispatch(resetIdentity())
}
9 changes: 8 additions & 1 deletion src/app/state/reducers/datavault.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { configureStore, Store, AnyAction } from '@reduxjs/toolkit'
import dataVaultSlice, { DataVaultState, receiveKeyData, initialState, addContentToKey, removeContentfromKey, swapContentById, DataVaultContent, receiveStorageInformation, receiveKeys } from './datavault'
import dataVaultSlice, { DataVaultState, receiveKeyData, initialState, addContentToKey, removeContentfromKey, swapContentById, DataVaultContent, receiveStorageInformation, receiveKeys, reset } from './datavault'

describe('dataVault slice', () => {
describe('action creators', () => {
Expand Down Expand Up @@ -45,6 +45,13 @@ describe('dataVault slice', () => {
expect(store.getState()).toEqual(initialState)
})

test('it resets', () => {
store.dispatch(receiveKeys({ keys: ['oneDD', 'twoCredential'] }))
store.dispatch(addContentToKey({ key: 'twoCredential', content: { id: '2', content: 'bye' } }))
store.dispatch(reset())
expect(store.getState()).toEqual(initialState)
})

describe('receiveKeyData', () => {
test('receiveKeyData', () => {
const content = [{ id: '1', content: 'hello' }, { id: '2', content: 'bye' }]
Expand Down
5 changes: 3 additions & 2 deletions src/app/state/reducers/datavault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ const dataVaultSlice = createSlice({
keys.forEach((key: string) => {
key.endsWith('Credential') ? state.credentials[key] = [] : state.declarativeDetails[key] = []
})
}
},
reset: _state => initialState
}
})

export const { receiveKeyData, addContentToKey, removeContentfromKey, swapContentById, receiveStorageInformation, receiveKeys } = dataVaultSlice.actions
export const { receiveKeyData, addContentToKey, removeContentfromKey, swapContentById, receiveStorageInformation, receiveKeys, reset } = dataVaultSlice.actions

export default dataVaultSlice.reducer
10 changes: 9 additions & 1 deletion src/app/state/reducers/defi.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { configureStore, Store, AnyAction } from '@reduxjs/toolkit'
import tokenSlice, { addTokenData, DefiState, initialState, tokenInitialState, receiveBalance, receiveConversionBalance } from './defi'
import tokenSlice, { addTokenData, DefiState, initialState, tokenInitialState, receiveBalance, receiveConversionBalance, reset } from './defi'

describe('token slide', () => {
describe('action creators', () => {
Expand Down Expand Up @@ -87,5 +87,13 @@ describe('token slide', () => {
store.dispatch(receiveConversionBalance({ usd: 18 }))
expect(store.getState().conversion).toEqual(18)
})

test('reset', () => {
store.dispatch(receiveBalance({ balance: 1.846 }))
store.dispatch(receiveConversionBalance({ usd: 18 }))
store.dispatch(addTokenData({ data: { address: '0x123', name: 'test' } }))
store.dispatch(reset())
expect(store.getState()).toEqual(initialState)
})
})
})
5 changes: 3 additions & 2 deletions src/app/state/reducers/defi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ const defiSlice = createSlice({
},
receiveConversionBalance (state: DefiState, { payload: { usd } }: PayloadAction<{ usd: number }>) {
state.conversion = usd
}
},
reset: _state => initialState
}
})

export const { addTokenData, receiveBalance, receiveConversionBalance } = defiSlice.actions
export const { addTokenData, receiveBalance, receiveConversionBalance, reset } = defiSlice.actions

export default defiSlice.reducer
8 changes: 7 additions & 1 deletion src/app/state/reducers/ethrdid.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { configureStore, Store, AnyAction } from '@reduxjs/toolkit'
import { DIDDocument } from 'did-resolver'
import ethrdidSlice, { EtherdidState, initialState, resolveDid } from './ethrdid'
import ethrdidSlice, { EtherdidState, initialState, reset, resolveDid } from './ethrdid'

describe('ethrdid slice', () => {
const data: DIDDocument = {
Expand Down Expand Up @@ -34,5 +34,11 @@ describe('ethrdid slice', () => {
didDocument: data
})
})

test('reset', () => {
store.dispatch(resolveDid({ data }))
store.dispatch(reset())
expect(store.getState()).toEqual(initialState)
})
})
})
5 changes: 3 additions & 2 deletions src/app/state/reducers/ethrdid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ const ethrDidSlice = createSlice({
reducers: {
resolveDid (state: EtherdidState, { payload: { data } }: PayloadAction<ResolveDidPayload>) {
state.didDocument = data
}
},
reset: _state => initialState
}
})

export const { resolveDid } = ethrDidSlice.actions
export const { resolveDid, reset } = ethrDidSlice.actions

export default ethrDidSlice.reducer
9 changes: 8 additions & 1 deletion src/app/state/reducers/identity.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { configureStore, Store, AnyAction } from '@reduxjs/toolkit'
import identitySlice, { changeAccount, changeChainId, IdentityState, initialState } from './identity'
import identitySlice, { changeAccount, changeChainId, IdentityState, initialState, reset } from './identity'

describe('identity slide', () => {
const address = '0xf3beac30c498d9e26865f34fcaa57dbb935b0d74'
Expand Down Expand Up @@ -39,5 +39,12 @@ describe('identity slide', () => {
chainId: 30
})
})

test('reset', () => {
store.dispatch(changeAccount({ address }))
store.dispatch(changeChainId({ chainId: 30 }))
store.dispatch(reset())
expect(store.getState()).toEqual(initialState)
})
})
})
5 changes: 3 additions & 2 deletions src/app/state/reducers/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ const identitySlice = createSlice({
},
changeChainId (state: IdentityState, { payload: { chainId } }: PayloadAction<ChangeChainIdPayload>) {
state.chainId = chainId
}
},
reset: _state => initialState
}
})

export const { changeAccount, changeChainId } = identitySlice.actions
export const { changeAccount, changeChainId, reset } = identitySlice.actions

export default identitySlice.reducer
8 changes: 8 additions & 0 deletions src/assets/scss/components/_navigation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ ul.navigation {
li.disabled {
color: $lightGray;
}

li.logout {
float: right
}
}

@media screen and (max-width: $breakpoint-phone) {
Expand All @@ -42,5 +46,9 @@ ul.navigation {
display: block;
padding: 5px 0;
}

li.logout {
float: none
}
}
}
12 changes: 12 additions & 0 deletions src/features/rLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,15 @@ export const rLogin = new RLogin({
},
supportedChains: [1, 30, 31, 5777]
})

export const clearRloginStorage = () => {
localStorage.removeItem('RLOGIN_ACCESS_TOKEN')
localStorage.removeItem('RLOGIN_REFRESH_TOKEN')
localStorage.removeItem('walletconnect')

Object.keys(localStorage).map((key: string) => {
if (key.startsWith('DV_ACCESS_TOKEN') || key.startsWith('DV_REFRESH_TOKEN')) {
localStorage.removeItem(key)
}
})
}
10 changes: 8 additions & 2 deletions src/providerContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ export interface Web3ProviderContextInterface {
setProvider?: (value: any) => void
dvClient: DataVaultWebClient | null,
setDvClient?: (client: DataVaultWebClient) => void
reset: () => void
}

export const Web3ProviderContext = React.createContext<Web3ProviderContextInterface>({
provider: null,
dvClient: null
dvClient: null,
reset: () => {}
})

interface Web3ProviderElementInterface {
Expand All @@ -25,7 +27,11 @@ export const Web3ProviderElement: React.FC<Web3ProviderElementInterface> = ({ ch
provider: provider,
setProvider: (provider: any) => setProvider(provider),
dvClient: dvClient,
setDvClient: (client: DataVaultWebClient) => setDvClient(client)
setDvClient: (client: DataVaultWebClient | null) => setDvClient(client),
reset: () => {
setProvider(null)
setDvClient(null)
}
}

return (
Expand Down