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