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

Commit

Permalink
useKeystoreAccounts / useKeystoreState hooks (#2346)
Browse files Browse the repository at this point in the history
+ `keystoreAccountsUI$`
  • Loading branch information
veado authored Aug 9, 2022
1 parent 315be6f commit c0fc928
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 18 deletions.
21 changes: 21 additions & 0 deletions src/renderer/hooks/useKeystoreAccounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as RD from '@devexperts/remote-data-ts'
import * as FP from 'fp-ts/lib/function'
import { useObservableState } from 'observable-hooks'

import { useWalletContext } from '../contexts/WalletContext'
import { KeystoreAccountsRD, KeystoreAccountsUI } from '../services/wallet/types'

export const useKeystoreAccounts = (): {
keystoreAccounts: KeystoreAccountsRD
reloadKeystoreAccounts: FP.Lazy<void>
keystoreAccountsUI: KeystoreAccountsUI
} => {
const {
keystoreService: { reloadKeystoreAccounts, keystoreAccounts$, keystoreAccountsUI$ }
} = useWalletContext()

const keystoreAccounts = useObservableState(keystoreAccounts$, RD.initial)
const keystoreAccountsUI = useObservableState(keystoreAccountsUI$, [])

return { keystoreAccounts, keystoreAccountsUI, reloadKeystoreAccounts }
}
29 changes: 29 additions & 0 deletions src/renderer/hooks/useKeystoreState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as FP from 'fp-ts/lib/function'
import * as O from 'fp-ts/lib/Option'
import { useObservableState } from 'observable-hooks'
import * as RxOp from 'rxjs/operators'

import { useWalletContext } from '../contexts/WalletContext'
import { INITIAL_KEYSTORE_STATE } from '../services/wallet/const'
import { KeystoreState, Phrase } from '../services/wallet/types'
import { getPhrase, getWalletName } from '../services/wallet/util'

export const useKeystoreState = (): {
state: KeystoreState
phrase: O.Option<Phrase>
walletName: O.Option<string>
remove: () => Promise<void>
unlock: (password: string) => Promise<void>
lock: FP.Lazy<void>
} => {
const {
keystoreService: { keystore$, unlock, lock, removeKeystoreAccount: remove }
} = useWalletContext()

const state = useObservableState(keystore$, INITIAL_KEYSTORE_STATE)

const [phrase] = useObservableState(() => FP.pipe(keystore$, RxOp.map(FP.flow(getPhrase))), O.none)
const [walletName] = useObservableState(() => FP.pipe(keystore$, RxOp.map(FP.flow(getWalletName))), O.none)

return { state, phrase, walletName, unlock, lock, remove }
}
15 changes: 14 additions & 1 deletion src/renderer/services/wallet/keystore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
LoadKeystoreLD,
ImportKeystoreParams,
AddKeystoreParams,
KeystoreAccountsLD
KeystoreAccountsLD,
KeystoreAccountsUI$
} from './types'
import {
getKeystore,
Expand All @@ -39,6 +40,9 @@ const {
set: setKeystoreState
} = observableState<KeystoreState>(INITIAL_KEYSTORE_STATE)

/**
* Internal state of keystore accounts - not shared to outside world
*/
const {
get$: getKeystoreAccounts$,
get: getKeystoreAccounts,
Expand Down Expand Up @@ -215,6 +219,14 @@ const keystoreAccounts$: KeystoreAccountsLD = FP.pipe(
RxOp.startWith(RD.pending)
)

// Simplified `KeystoreAccounts` (w/o loading state, w/o `keystore`) to display data at UIs
const keystoreAccountsUI$: KeystoreAccountsUI$ = FP.pipe(
getKeystoreAccounts$,
// Transform `KeystoreAccounts` -> `KeystoreAccountsUI`
RxOp.map(FP.flow(A.map(({ id, name, selected }) => ({ id, name, selected })))),
RxOp.shareReplay(1)
)

const id = FP.pipe(getKeystoreState(), getKeystoreId)
if (!id) {
throw Error(`Can't export keystore - keystore id is missing in KeystoreState`)
Expand Down Expand Up @@ -251,6 +263,7 @@ export const keystoreService: KeystoreService = {
unlock,
validatePassword$,
reloadKeystoreAccounts,
keystoreAccountsUI$,
keystoreAccounts$
}

Expand Down
8 changes: 7 additions & 1 deletion src/renderer/services/wallet/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
import * as O from 'fp-ts/lib/Option'
import * as Rx from 'rxjs'

import { KeystoreAccounts } from '../../../shared/api/io'
import { KeystoreAccount, KeystoreAccounts } from '../../../shared/api/io'
import { KeystoreId, LedgerError, Network } from '../../../shared/api/types'
import { WalletAddress, WalletBalanceType, WalletType } from '../../../shared/wallet/types'
import { LiveData } from '../../helpers/rx/liveData'
Expand Down Expand Up @@ -72,6 +72,7 @@ export type KeystoreService = {
validatePassword$: ValidatePasswordHandler
reloadKeystoreAccounts: FP.Lazy<void>
keystoreAccounts$: KeystoreAccountsLD
keystoreAccountsUI$: KeystoreAccountsUI$
}

export type WalletAddressAsync = { address: RD.RemoteData<Error, WalletAddress>; type: WalletType }
Expand Down Expand Up @@ -207,4 +208,9 @@ export type LedgerAddressMap$ = Rx.Observable<LedgerAddressMap>
export type LedgerAddressesMap = Record<Chain, LedgerAddressMap>
export type LedgerAddressesMap$ = Rx.Observable<LedgerAddressesMap>

export type KeystoreAccountsRD = RD.RemoteData<Error, KeystoreAccounts>
export type KeystoreAccountsLD = LiveData<Error, KeystoreAccounts>

export type KeystoreAccountUI = Omit<KeystoreAccount, 'keystore'>
export type KeystoreAccountsUI = KeystoreAccountUI[]
export type KeystoreAccountsUI$ = Rx.Observable<KeystoreAccountsUI>
8 changes: 2 additions & 6 deletions src/renderer/views/app/AppView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import { Header } from '../../components/header'
import { Button } from '../../components/uielements/button'
import { useI18nContext } from '../../contexts/I18nContext'
import { useMidgardContext } from '../../contexts/MidgardContext'
import { useWalletContext } from '../../contexts/WalletContext'
import { unionChains } from '../../helpers/fp/array'
import { rdAltOnPending } from '../../helpers/fpHelpers'
import { useKeystoreAccounts } from '../../hooks/useKeystoreAccounts'
import { useMimirHalt } from '../../hooks/useMimirHalt'
import { useTheme } from '../../hooks/useTheme'
import { DEFAULT_MIMIR_HALT } from '../../services/thorchain/const'
Expand Down Expand Up @@ -72,11 +72,7 @@ export const AppView: React.FC = (): JSX.Element => {
const prevHaltedChains = useRef<Chain[]>([])
const prevMimirHalt = useRef<MimirHalt>(DEFAULT_MIMIR_HALT)

const {
keystoreService: { reloadKeystoreAccounts, keystoreAccounts$ }
} = useWalletContext()

const keystoreAccounts = useObservableState(keystoreAccounts$, RD.initial)
const { keystoreAccounts, reloadKeystoreAccounts } = useKeystoreAccounts()

const { mimirHaltRD } = useMimirHalt()

Expand Down
13 changes: 3 additions & 10 deletions src/renderer/views/wallet/UnlockView.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import React from 'react'

import { useObservableState } from 'observable-hooks'

import { UnlockForm } from '../../components/wallet/unlock'
import { useWalletContext } from '../../contexts/WalletContext'
import { INITIAL_KEYSTORE_STATE } from '../../services/wallet/const'
import { useKeystoreState } from '../../hooks/useKeystoreState'

export const UnlockView: React.FC = (): JSX.Element => {
const {
keystoreService: { keystore$, removeKeystoreAccount, unlock }
} = useWalletContext()
const keystore = useObservableState(keystore$, INITIAL_KEYSTORE_STATE)

return <UnlockForm keystore={keystore} unlock={unlock} removeKeystore={removeKeystoreAccount} />
const { state: keystore, unlock, remove } = useKeystoreState()
return <UnlockForm keystore={keystore} unlock={unlock} removeKeystore={remove} />
}

0 comments on commit c0fc928

Please sign in to comment.