diff --git a/pages/wallets/index.js b/pages/wallets/index.js index a547e9ed..78ac45a5 100644 --- a/pages/wallets/index.js +++ b/pages/wallets/index.js @@ -68,6 +68,19 @@ export default function Wallet () { ) } + if (status instanceof Error) { + return ( + + + failed to load wallets + + {status.message} + + + + ) + } + if (status === Status.NO_WALLETS && !showWallets) { return ( diff --git a/wallets/client/context/hooks.js b/wallets/client/context/hooks.js index 89255cd9..aab7cda1 100644 --- a/wallets/client/context/hooks.js +++ b/wallets/client/context/hooks.js @@ -9,7 +9,7 @@ import { useWalletMigrationMutation, CryptoKeyRequiredError, useIsWrongKey } from '@/wallets/client/hooks' import { WalletConfigurationError } from '@/wallets/client/errors' -import { SET_WALLETS, WRONG_KEY, KEY_MATCH, NO_KEY, useWalletsDispatch } from '@/wallets/client/context' +import { SET_WALLETS, WRONG_KEY, KEY_MATCH, NO_KEY, useWalletsDispatch, WALLETS_QUERY_ERROR } from '@/wallets/client/context' import { useIndexedDB } from '@/components/use-indexeddb' export function useServerWallets () { @@ -19,6 +19,7 @@ export function useServerWallets () { useEffect(() => { if (query.error) { console.error('failed to fetch wallets:', query.error) + dispatch({ type: WALLETS_QUERY_ERROR, error: query.error }) return } if (query.loading) return diff --git a/wallets/client/context/reducer.js b/wallets/client/context/reducer.js index b0cbe09b..365c2475 100644 --- a/wallets/client/context/reducer.js +++ b/wallets/client/context/reducer.js @@ -15,6 +15,7 @@ export const SET_KEY = 'SET_KEY' export const WRONG_KEY = 'WRONG_KEY' export const KEY_MATCH = 'KEY_MATCH' export const NO_KEY = 'KEY_UNAVAILABLE' +export const WALLETS_QUERY_ERROR = 'WALLETS_QUERY_ERROR' export default function reducer (state, action) { switch (action.type) { @@ -32,6 +33,11 @@ export default function reducer (state, action) { templates } } + case WALLETS_QUERY_ERROR: + return { + ...state, + status: transitionStatus(action, state, action.error) + } case SET_KEY: return { ...state, @@ -61,10 +67,10 @@ export default function reducer (state, action) { function transitionStatus ({ type }, { status: from }, to) { switch (type) { case SET_WALLETS: { - return [Status.PASSPHRASE_REQUIRED, Status.WALLETS_UNAVAILABLE].includes(from) ? from : to + return (from instanceof Error || [Status.PASSPHRASE_REQUIRED, Status.WALLETS_UNAVAILABLE].includes(from)) ? from : to } case KEY_MATCH: { - return from === Status.LOADING_WALLETS ? from : to + return (from instanceof Error || from === Status.LOADING_WALLETS) ? from : to } default: return to diff --git a/wallets/client/hooks/query.js b/wallets/client/hooks/query.js index 9e1e97cf..177bcf3e 100644 --- a/wallets/client/hooks/query.js +++ b/wallets/client/hooks/query.js @@ -38,6 +38,7 @@ export function useWalletsQuery () { const { me } = useMe() const query = useQuery(WALLETS, { skip: !me }) const [wallets, setWallets] = useState(null) + const [error, setError] = useState(null) const { decryptWallet, ready } = useWalletDecryption() @@ -48,10 +49,14 @@ export function useWalletsQuery () { ) .then(wallets => wallets.map(protocolCheck)) .then(wallets => wallets.map(undoFieldAlias)) - .then(wallets => setWallets(wallets)) + .then(wallets => { + setWallets(wallets) + setError(null) + }) .catch(err => { console.error('failed to decrypt wallets:', err) setWallets([]) + setError(new Error('decryption error: ' + err.message)) }) }, [query.data, decryptWallet, ready]) @@ -59,9 +64,10 @@ export function useWalletsQuery () { return useMemo(() => ({ ...query, + error: error ?? query.error, loading: !wallets, data: wallets ? { wallets } : null - }), [query, wallets]) + }), [query, error, wallets]) } function protocolCheck (wallet) {