@@ -81,9 +77,14 @@ function WalletFormSelector () {
}
function WalletSendRecvSelector () {
+ const wallet = useWallet()
const path = useWalletPathname()
+ const protocols = useProtocolTemplates(wallet)
const selected = useSendRecvParam()
+ const firstSend = protocols.find(p => p.send)
+ const firstRecv = protocols.find(p => !p.send)
+
// TODO(wallet-v2): if you click a nav link again, it will update the URL
// but not run the effect again to select the first protocol by default
return (
@@ -93,12 +94,12 @@ function WalletSendRecvSelector () {
activeKey={selected}
>
-
+
SEND
-
+
RECEIVE
@@ -109,17 +110,11 @@ function WalletSendRecvSelector () {
function WalletProtocolSelector () {
const walletPath = useWalletPathname()
const sendRecvParam = useSendRecvParam()
+ const selected = useWalletProtocolParam()
const path = `${walletPath}/${sendRecvParam}`
- const protocols = useWalletProtocols()
- const selected = useWalletProtocolParam()
- const router = useRouter()
-
- useEffect(() => {
- if (!selected && protocols.length > 0) {
- router.replace(`/${path}/${urlify(protocols[0].name)}`, null, { shallow: true })
- }
- }, [path])
+ const wallet = useWallet()
+ const protocols = useProtocolTemplates(wallet).filter(p => sendRecvParam === 'send' ? p.send : !p.send)
if (protocols.length === 0) {
// TODO(wallet-v2): let user know how to request support if the wallet actually does support sending
@@ -179,7 +174,7 @@ function WalletProtocolForm () {
return
}
// we just created a new user wallet from a template
- router.replace(`/wallets/${upsert.id}/${sendRecvParam}`, null, { shallow: true })
+ router.replace(`/wallets/${upsert.id}/${sendRecvParam}/${urlify(protocol.name)}`, null, { shallow: true })
toaster.success('wallet attached', { persistOnNavigate: true })
}, [upsertWalletProtocol, toaster, wallet, router])
@@ -303,17 +298,6 @@ function useWalletProtocolParam () {
return name ? unurlify(name) : null
}
-function useWalletProtocols () {
- const wallet = useWallet()
- const sendRecvParam = useSendRecvParam()
- if (!sendRecvParam) return []
-
- const protocolFilter = p => sendRecvParam === 'send' ? p.send : !p.send
- return isWallet(wallet)
- ? wallet.template.protocols.filter(protocolFilter)
- : wallet.protocols.filter(protocolFilter)
-}
-
function useSelectedProtocol () {
const wallet = useWallet()
const sendRecvParam = useSendRecvParam()
diff --git a/wallets/client/hooks/query.js b/wallets/client/hooks/query.js
index 71cf7a0e..c196f067 100644
--- a/wallets/client/hooks/query.js
+++ b/wallets/client/hooks/query.js
@@ -1,5 +1,4 @@
import {
- WALLET,
UPSERT_WALLET_RECEIVE_BLINK,
UPSERT_WALLET_RECEIVE_CLN_REST,
UPSERT_WALLET_RECEIVE_LIGHTNING_ADDRESS,
@@ -55,8 +54,7 @@ export function useWalletsQuery () {
Promise.all(
query.data?.wallets.map(w => decryptWallet(w))
)
- .then(wallets => wallets.map(protocolCheck))
- .then(wallets => wallets.map(undoFieldAlias))
+ .then(wallets => wallets.map(server2Client))
.then(wallets => {
setWallets(wallets)
setError(null)
@@ -79,41 +77,6 @@ export function useWalletsQuery () {
}), [query, error, wallets])
}
-function protocolCheck (wallet) {
- if (isTemplate(wallet)) return wallet
-
- const protocols = wallet.protocols.map(protocol => {
- return {
- ...protocol,
- enabled: protocol.enabled && protocolAvailable(protocol)
- }
- })
-
- const sendEnabled = protocols.some(p => p.send && p.enabled)
- const receiveEnabled = protocols.some(p => !p.send && p.enabled)
-
- return {
- ...wallet,
- send: !sendEnabled ? WalletStatus.DISABLED : wallet.send,
- receive: !receiveEnabled ? WalletStatus.DISABLED : wallet.receive,
- protocols
- }
-}
-
-function undoFieldAlias ({ id, ...wallet }) {
- // Just like for encrypted fields, we have to use a field alias for the name field of templates
- // because of https://github.com/graphql/graphql-js/issues/53.
- // We undo this here so this only affects the GraphQL layer but not the rest of the code.
- if (isTemplate(wallet)) {
- return { ...wallet, name: id }
- }
-
- if (!wallet.template) return wallet
-
- const { id: templateId, ...template } = wallet.template
- return { id, ...wallet, template: { name: templateId, ...template } }
-}
-
function useRefetchOnChange (refetch) {
const { me } = useMe()
const walletsUpdatedAt = useWalletsUpdatedAt()
@@ -125,29 +88,62 @@ function useRefetchOnChange (refetch) {
}, [refetch, me?.id, walletsUpdatedAt])
}
-export function useWalletQuery ({ id, name }) {
- const { me } = useMe()
- const query = useQuery(WALLET, { variables: { id, name }, skip: !me })
- const [wallet, setWallet] = useState(null)
-
+export function useDecryptedWallet (wallet) {
const { decryptWallet, ready } = useWalletDecryption()
+ const [decryptedWallet, setDecryptedWallet] = useState(server2Client(wallet))
useEffect(() => {
- if (!query.data?.wallet || !ready) return
- decryptWallet(query.data?.wallet)
- .then(protocolCheck)
- .then(undoFieldAlias)
- .then(wallet => setWallet(wallet))
+ if (!ready || !wallet) return
+ decryptWallet(wallet)
+ .then(server2Client)
+ .then(wallet => setDecryptedWallet(wallet))
.catch(err => {
console.error('failed to decrypt wallet:', err)
})
- }, [query.data, decryptWallet, ready])
+ }, [decryptWallet, wallet, ready])
- return useMemo(() => ({
- ...query,
- loading: !wallet,
- data: wallet ? { wallet } : null
- }), [query, wallet])
+ return decryptedWallet
+}
+
+function server2Client (wallet) {
+ // some protocols require a specific client environment
+ // e.g. WebLN requires a browser extension
+ function checkProtocolAvailability (wallet) {
+ if (isTemplate(wallet)) return wallet
+
+ const protocols = wallet.protocols.map(protocol => {
+ return {
+ ...protocol,
+ enabled: protocol.enabled && protocolAvailable(protocol)
+ }
+ })
+
+ const sendEnabled = protocols.some(p => p.send && p.enabled)
+ const receiveEnabled = protocols.some(p => !p.send && p.enabled)
+
+ return {
+ ...wallet,
+ send: !sendEnabled ? WalletStatus.DISABLED : wallet.send,
+ receive: !receiveEnabled ? WalletStatus.DISABLED : wallet.receive,
+ protocols
+ }
+ }
+
+ // Just like for encrypted fields, we have to use a field alias for the name field of templates
+ // because of https://github.com/graphql/graphql-js/issues/53.
+ // We undo this here so this only affects the GraphQL layer but not the rest of the code.
+ function undoFieldAlias ({ id, ...wallet }) {
+ if (isTemplate(wallet)) {
+ return { ...wallet, name: id }
+ }
+
+ if (!wallet.template) return wallet
+
+ const { id: templateId, ...template } = wallet.template
+ return { id, ...wallet, template: { name: templateId, ...template } }
+ }
+
+ return wallet ? undoFieldAlias(checkProtocolAvailability(wallet)) : wallet
}
export function useWalletProtocolUpsert (wallet, protocol) {
diff --git a/wallets/client/hooks/wallet.js b/wallets/client/hooks/wallet.js
index 8a439825..18447454 100644
--- a/wallets/client/hooks/wallet.js
+++ b/wallets/client/hooks/wallet.js
@@ -53,3 +53,9 @@ export function useWalletsUpdatedAt () {
const { me } = useMe()
return me?.privates?.walletsUpdatedAt
}
+
+export function useProtocolTemplates (wallet) {
+ return useMemo(() => {
+ return isWallet(wallet) ? wallet.template.protocols : wallet.protocols
+ }, [wallet])
+}
diff --git a/wallets/lib/util.js b/wallets/lib/util.js
index 9c606adb..eabb754f 100644
--- a/wallets/lib/util.js
+++ b/wallets/lib/util.js
@@ -1,6 +1,7 @@
import * as yup from 'yup'
import wallets from '@/wallets/lib/wallets.json'
import protocols from '@/wallets/lib/protocols'
+import { SSR } from '@/lib/constants'
function walletJson (name) {
return wallets.find(wallet => wallet.name === name)
@@ -88,7 +89,7 @@ export function protocolFields ({ name, send }) {
export function protocolAvailable ({ name, send }) {
const { isAvailable } = protocol({ name, send })
- if (typeof isAvailable === 'function') {
+ if (!SSR && typeof isAvailable === 'function') {
return isAvailable()
}
diff --git a/wallets/server/resolvers/wallet.js b/wallets/server/resolvers/wallet.js
index e07368d5..c1902a25 100644
--- a/wallets/server/resolvers/wallet.js
+++ b/wallets/server/resolvers/wallet.js
@@ -96,6 +96,8 @@ async function wallet (parent, { id, name }, { me, models }) {
protocols: true
}
})
+ if (!wallet) throw new GqlInputError('wallet not found')
+
return mapWalletResolveTypes(wallet)
}