Fix wallets error handling order (#2286)
This commit is contained in:
		
							parent
							
								
									2ee685d5a9
								
							
						
					
					
						commit
						5502d29d7e
					
				@ -1,6 +1,6 @@
 | 
			
		||||
import { getGetServerSideProps } from '@/api/ssrApollo'
 | 
			
		||||
import { Button } from 'react-bootstrap'
 | 
			
		||||
import { useWallets, useTemplates, DndProvider, Status, useStatus } from '@/wallets/client/context'
 | 
			
		||||
import { useWallets, useTemplates, DndProvider, KeyStatus, useWalletsLoading, useKeyError, useWalletsError } from '@/wallets/client/context'
 | 
			
		||||
import { WalletCard, WalletLayout, WalletLayoutHeader, WalletLayoutLink, WalletLayoutSubHeader } from '@/wallets/client/components'
 | 
			
		||||
import styles from '@/styles/wallet.module.css'
 | 
			
		||||
import { usePassphrasePrompt, useShowPassphrase, useSetWalletPriorities } from '@/wallets/client/hooks'
 | 
			
		||||
@ -13,7 +13,9 @@ export const getServerSideProps = getGetServerSideProps({ authRequired: true })
 | 
			
		||||
 | 
			
		||||
export default function Wallet () {
 | 
			
		||||
  const wallets = useWallets()
 | 
			
		||||
  const status = useStatus()
 | 
			
		||||
  const walletsLoading = useWalletsLoading()
 | 
			
		||||
  const walletsError = useWalletsError()
 | 
			
		||||
  const keyError = useKeyError()
 | 
			
		||||
  const [showWallets, setShowWallets] = useState(false)
 | 
			
		||||
  const templates = useTemplates()
 | 
			
		||||
  const showPassphrase = useShowPassphrase()
 | 
			
		||||
@ -29,18 +31,20 @@ export default function Wallet () {
 | 
			
		||||
    }
 | 
			
		||||
  }, [wallets, templates, searchFilter])
 | 
			
		||||
 | 
			
		||||
  if (status === Status.LOADING_WALLETS) {
 | 
			
		||||
  if (keyError === KeyStatus.KEY_STORAGE_UNAVAILABLE) {
 | 
			
		||||
    return (
 | 
			
		||||
      <WalletLayout>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1 text-muted'>
 | 
			
		||||
          <Moon className='spin fill-grey' height={28} width={28} />
 | 
			
		||||
          <small className='d-block mt-3 text-muted'>loading wallets</small>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1'>
 | 
			
		||||
          <span className='text-muted fw-bold my-1'>wallets unavailable</span>
 | 
			
		||||
          <small className='d-block text-muted'>
 | 
			
		||||
            this device does not support storage of cryptographic keys via IndexedDB
 | 
			
		||||
          </small>
 | 
			
		||||
        </div>
 | 
			
		||||
      </WalletLayout>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (status === Status.PASSPHRASE_REQUIRED) {
 | 
			
		||||
  if (keyError === KeyStatus.WRONG_KEY) {
 | 
			
		||||
    return (
 | 
			
		||||
      <WalletLayout>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1'>
 | 
			
		||||
@ -55,33 +59,31 @@ export default function Wallet () {
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (status === Status.WALLETS_UNAVAILABLE) {
 | 
			
		||||
    return (
 | 
			
		||||
      <WalletLayout>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1'>
 | 
			
		||||
          <span className='text-muted fw-bold my-1'>wallets unavailable</span>
 | 
			
		||||
          <small className='d-block text-muted'>
 | 
			
		||||
            this device does not support storage of cryptographic keys via IndexedDB
 | 
			
		||||
          </small>
 | 
			
		||||
        </div>
 | 
			
		||||
      </WalletLayout>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (status instanceof Error) {
 | 
			
		||||
  if (walletsError) {
 | 
			
		||||
    return (
 | 
			
		||||
      <WalletLayout>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1'>
 | 
			
		||||
          <span className='text-muted fw-bold my-1'>failed to load wallets</span>
 | 
			
		||||
          <small className='d-block text-muted'>
 | 
			
		||||
            {status.message}
 | 
			
		||||
            {walletsError.message}
 | 
			
		||||
          </small>
 | 
			
		||||
        </div>
 | 
			
		||||
      </WalletLayout>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (status === Status.NO_WALLETS && !showWallets) {
 | 
			
		||||
  if (walletsLoading) {
 | 
			
		||||
    return (
 | 
			
		||||
      <WalletLayout>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1 text-muted'>
 | 
			
		||||
          <Moon className='spin fill-grey' height={28} width={28} />
 | 
			
		||||
          <small className='d-block mt-3 text-muted'>loading wallets</small>
 | 
			
		||||
        </div>
 | 
			
		||||
      </WalletLayout>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (wallets.length === 0 && !showWallets) {
 | 
			
		||||
    return (
 | 
			
		||||
      <WalletLayout>
 | 
			
		||||
        <div className='py-5 text-center d-flex flex-column align-items-center justify-content-center flex-grow-1'>
 | 
			
		||||
 | 
			
		||||
@ -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, WALLETS_QUERY_ERROR } from '@/wallets/client/context'
 | 
			
		||||
import { SET_WALLETS, WRONG_KEY, KEY_MATCH, useWalletsDispatch, WALLETS_QUERY_ERROR, KEY_STORAGE_UNAVAILABLE } from '@/wallets/client/context'
 | 
			
		||||
import { useIndexedDB } from '@/components/use-indexeddb'
 | 
			
		||||
 | 
			
		||||
export function useServerWallets () {
 | 
			
		||||
@ -110,7 +110,7 @@ export function useKeyInit () {
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (typeof window.indexedDB === 'undefined') {
 | 
			
		||||
      dispatch({ type: NO_KEY })
 | 
			
		||||
      dispatch({ type: KEY_STORAGE_UNAVAILABLE })
 | 
			
		||||
    } else if (wrongKey) {
 | 
			
		||||
      dispatch({ type: WRONG_KEY })
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { createContext, useContext, useReducer } from 'react'
 | 
			
		||||
import walletsReducer, { Status } from './reducer'
 | 
			
		||||
import walletsReducer from './reducer'
 | 
			
		||||
import { useServerWallets, useKeyCheck, useAutomatedRetries, useKeyInit, useWalletMigration } from './hooks'
 | 
			
		||||
import { WebLnProvider } from '@/wallets/lib/protocols/webln'
 | 
			
		||||
 | 
			
		||||
@ -17,14 +17,14 @@ export function useTemplates () {
 | 
			
		||||
  return templates
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useLoading () {
 | 
			
		||||
  const { status } = useContext(WalletsContext)
 | 
			
		||||
  return status === Status.LOADING_WALLETS
 | 
			
		||||
export function useWalletsLoading () {
 | 
			
		||||
  const { walletsLoading } = useContext(WalletsContext)
 | 
			
		||||
  return walletsLoading
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useStatus () {
 | 
			
		||||
  const { status } = useContext(WalletsContext)
 | 
			
		||||
  return status
 | 
			
		||||
export function useWalletsError () {
 | 
			
		||||
  const { walletsError } = useContext(WalletsContext)
 | 
			
		||||
  return walletsError
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useWalletsDispatch () {
 | 
			
		||||
@ -41,13 +41,20 @@ export function useKeyHash () {
 | 
			
		||||
  return keyHash
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useKeyError () {
 | 
			
		||||
  const { keyError } = useContext(WalletsContext)
 | 
			
		||||
  return keyError
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function WalletsProvider ({ children }) {
 | 
			
		||||
  const [state, dispatch] = useReducer(walletsReducer, {
 | 
			
		||||
    status: Status.LOADING_WALLETS,
 | 
			
		||||
    wallets: [],
 | 
			
		||||
    walletsLoading: true,
 | 
			
		||||
    walletsError: null,
 | 
			
		||||
    templates: [],
 | 
			
		||||
    key: null,
 | 
			
		||||
    keyHash: null
 | 
			
		||||
    keyHash: null,
 | 
			
		||||
    keyError: null
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,9 @@
 | 
			
		||||
import { isTemplate, isWallet } from '@/wallets/lib/util'
 | 
			
		||||
 | 
			
		||||
// states that dictate if we show a button or wallets on the wallets page
 | 
			
		||||
export const Status = {
 | 
			
		||||
  LOADING_WALLETS: 'LOADING_WALLETS',
 | 
			
		||||
  NO_WALLETS: 'NO_WALLETS',
 | 
			
		||||
  HAS_WALLETS: 'HAS_WALLETS',
 | 
			
		||||
  PASSPHRASE_REQUIRED: 'PASSPHRASE_REQUIRED',
 | 
			
		||||
  WALLETS_UNAVAILABLE: 'WALLETS_UNAVAILABLE'
 | 
			
		||||
export const KeyStatus = {
 | 
			
		||||
  KEY_MATCH: 'KEY_MATCH',
 | 
			
		||||
  NO_KEY: 'NO_KEY',
 | 
			
		||||
  WRONG_KEY: 'WRONG_KEY'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wallet actions
 | 
			
		||||
@ -14,7 +11,7 @@ export const SET_WALLETS = 'SET_WALLETS'
 | 
			
		||||
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 KEY_STORAGE_UNAVAILABLE = 'KEY_STORAGE_UNAVAILABLE'
 | 
			
		||||
export const WALLETS_QUERY_ERROR = 'WALLETS_QUERY_ERROR'
 | 
			
		||||
 | 
			
		||||
export default function reducer (state, action) {
 | 
			
		||||
@ -28,7 +25,8 @@ export default function reducer (state, action) {
 | 
			
		||||
        .sort((a, b) => a.name.localeCompare(b.name))
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        status: transitionStatus(action, state, wallets.length > 0 ? Status.HAS_WALLETS : Status.NO_WALLETS),
 | 
			
		||||
        walletsLoading: false,
 | 
			
		||||
        walletsError: null,
 | 
			
		||||
        wallets,
 | 
			
		||||
        templates
 | 
			
		||||
      }
 | 
			
		||||
@ -36,7 +34,8 @@ export default function reducer (state, action) {
 | 
			
		||||
    case WALLETS_QUERY_ERROR:
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        status: transitionStatus(action, state, action.error)
 | 
			
		||||
        walletsLoading: false,
 | 
			
		||||
        walletsError: action.error
 | 
			
		||||
      }
 | 
			
		||||
    case SET_KEY:
 | 
			
		||||
      return {
 | 
			
		||||
@ -47,32 +46,19 @@ export default function reducer (state, action) {
 | 
			
		||||
    case WRONG_KEY:
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        status: transitionStatus(action, state, Status.PASSPHRASE_REQUIRED)
 | 
			
		||||
        keyError: KeyStatus.WRONG_KEY
 | 
			
		||||
      }
 | 
			
		||||
    case KEY_MATCH:
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        status: transitionStatus(action, state, state.wallets.length > 0 ? Status.HAS_WALLETS : Status.NO_WALLETS)
 | 
			
		||||
        keyError: null
 | 
			
		||||
      }
 | 
			
		||||
    case NO_KEY:
 | 
			
		||||
    case KEY_STORAGE_UNAVAILABLE:
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        status: transitionStatus(action, state, Status.WALLETS_UNAVAILABLE)
 | 
			
		||||
        keyError: KeyStatus.KEY_STORAGE_UNAVAILABLE
 | 
			
		||||
      }
 | 
			
		||||
    default:
 | 
			
		||||
      return state
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function transitionStatus ({ type }, { status: from }, to) {
 | 
			
		||||
  switch (type) {
 | 
			
		||||
    case SET_WALLETS: {
 | 
			
		||||
      return (from instanceof Error || [Status.PASSPHRASE_REQUIRED, Status.WALLETS_UNAVAILABLE].includes(from)) ? from : to
 | 
			
		||||
    }
 | 
			
		||||
    case KEY_MATCH: {
 | 
			
		||||
      return (from instanceof Error || from === Status.LOADING_WALLETS) ? from : to
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return to
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { useWallets, useLoading } from '@/wallets/client/context'
 | 
			
		||||
import { useWallets, useWalletsLoading } from '@/wallets/client/context'
 | 
			
		||||
 | 
			
		||||
export function useWalletIndicator () {
 | 
			
		||||
  const wallets = useWallets()
 | 
			
		||||
  const loading = useLoading()
 | 
			
		||||
  const loading = useWalletsLoading()
 | 
			
		||||
  return !loading && wallets.length === 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ import { timeoutSignal } from '@/lib/time'
 | 
			
		||||
import { WALLET_SEND_PAYMENT_TIMEOUT_MS } from '@/lib/constants'
 | 
			
		||||
import { useToast } from '@/components/toast'
 | 
			
		||||
import { useMe } from '@/components/me'
 | 
			
		||||
import { useWallets, useLoading as useWalletsLoading } from '@/wallets/client/context'
 | 
			
		||||
import { useWallets, useWalletsLoading } from '@/wallets/client/context'
 | 
			
		||||
 | 
			
		||||
export function useWalletsQuery () {
 | 
			
		||||
  const { me } = useMe()
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user