reorder priority

This commit is contained in:
k00b 2024-10-24 16:35:18 -05:00
parent ccdf346954
commit 57603a936f
5 changed files with 74 additions and 34 deletions

View File

@ -525,6 +525,15 @@ const resolvers = {
}
return { id }
},
setWalletPriority: async (parent, { id, priority }, { me, models }) => {
if (!me) {
throw new GqlAuthenticationError()
}
await models.wallet.update({ where: { userId: me.id, id: Number(id) }, data: { priority } })
return true
},
removeWallet: async (parent, { id }, { me, models }) => {
if (!me) {
throw new GqlAuthenticationError()

View File

@ -81,6 +81,7 @@ const typeDefs = `
dropBolt11(id: ID): Withdrawl
removeWallet(id: ID!): Boolean
deleteWalletLogs(wallet: String): Boolean
setWalletPriority(id: ID!, priority: Int!): Boolean
}
type Wallet {

View File

@ -190,3 +190,9 @@ export const WALLET_LOGS = gql`
}
}
`
export const SET_WALLET_PRIORITY = gql`
mutation SetWalletPriority($id: ID!, $priority: Int!) {
setWalletPriority(id: $id, priority: $priority)
}
`

View File

@ -3,65 +3,69 @@ import Layout from '@/components/layout'
import styles from '@/styles/wallet.module.css'
import Link from 'next/link'
import { useWallets } from '@/wallets/index'
import { useState } from 'react'
import { useCallback, useState } from 'react'
import { useIsClient } from '@/components/use-client'
import WalletCard from '@/components/wallet-card'
import { useToast } from '@/components/toast'
export const getServerSideProps = getGetServerSideProps({ authRequired: true })
async function reorder (wallets, sourceIndex, targetIndex) {
const newOrder = [...wallets]
const [source] = newOrder.splice(sourceIndex, 1)
const newTargetIndex = sourceIndex < targetIndex ? targetIndex - 1 : targetIndex
const append = sourceIndex < targetIndex
newOrder.splice(newTargetIndex + (append ? 1 : 0), 0, source)
await Promise.all(
newOrder.map((w, i) =>
w.setPriority(i).catch(console.error)
)
)
}
export default function Wallet ({ ssrData }) {
const { wallets } = useWallets()
const { wallets, setPriorities, reloadLocalWallets } = useWallets()
const toast = useToast()
const isClient = useIsClient()
const [sourceIndex, setSourceIndex] = useState(null)
const [targetIndex, setTargetIndex] = useState(null)
const onDragStart = (i) => (e) => {
const reorder = useCallback(async (sourceIndex, targetIndex) => {
const newOrder = [...wallets.filter(w => w.config?.enabled)]
const [source] = newOrder.splice(sourceIndex, 1)
const newTargetIndex = sourceIndex < targetIndex ? targetIndex - 1 : targetIndex
const priorities = newOrder.slice(0, newTargetIndex)
.concat(source)
.concat(newOrder.slice(newTargetIndex))
.map((w, i) => ({ wallet: w, priority: i }))
await setPriorities(priorities)
reloadLocalWallets()
}, [setPriorities, reloadLocalWallets, wallets])
const onDragStart = useCallback((i) => (e) => {
// e.dataTransfer.dropEffect = 'move'
// We can only use the DataTransfer API inside the drop event
// see https://html.spec.whatwg.org/multipage/dnd.html#security-risks-in-the-drag-and-drop-model
// e.dataTransfer.setData('text/plain', name)
// That's why we use React state instead
setSourceIndex(i)
}
}, [setSourceIndex])
const onDragEnter = (i) => (e) => {
const onDragEnter = useCallback((i) => (e) => {
setTargetIndex(i)
}
}, [setTargetIndex])
const onDragEnd = async (e) => {
const onReorderError = useCallback((err) => {
console.error(err)
toast.danger('failed to reorder wallets')
}, [toast])
const onDragEnd = useCallback((e) => {
setSourceIndex(null)
setTargetIndex(null)
if (sourceIndex === targetIndex) return
await reorder(wallets, sourceIndex, targetIndex)
}
reorder(sourceIndex, targetIndex).catch(onReorderError)
}, [sourceIndex, targetIndex, reorder, onReorderError])
const onTouchStart = (i) => async (e) => {
const onTouchStart = useCallback((i) => (e) => {
if (sourceIndex !== null) {
await reorder(wallets, sourceIndex, i)
reorder(sourceIndex, i).catch(onReorderError)
setSourceIndex(null)
} else {
setSourceIndex(i)
}
}
}, [sourceIndex, reorder, onReorderError])
return (
<Layout>

View File

@ -1,9 +1,9 @@
import { useMe } from '@/components/me'
import { WALLETS } from '@/fragments/wallet'
import { SET_WALLET_PRIORITY, WALLETS } from '@/fragments/wallet'
import { SSR } from '@/lib/constants'
import { useQuery } from '@apollo/client'
import { useMutation, useQuery } from '@apollo/client'
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { getStorageKey, getWalletByType, Status, walletPrioritySort, canSend } from './common'
import { getStorageKey, getWalletByType, Status, walletPrioritySort, canSend, isConfigured } from './common'
import useVault from '@/components/vault/use-vault'
import { useWalletLogger } from '@/components/wallet-logger'
import { bolt11Tags } from '@/lib/bolt11'
@ -21,7 +21,8 @@ function useLocalWallets () {
// form wallets into a list of { config, def }
const wallets = walletDefs.map(w => {
try {
const config = window.localStorage.getItem(getStorageKey(w.name, me?.id))
const storageKey = getStorageKey(w.name, me?.id)
const config = window.localStorage.getItem(storageKey)
return { def: w, config: JSON.parse(config) }
} catch (e) {
return null
@ -43,10 +44,12 @@ export function WalletsProvider ({ children }) {
const { decrypt } = useVault()
const { me } = useMe()
const { wallets: localWallets, reloadLocalWallets } = useLocalWallets()
const [setWalletPriority] = useMutation(SET_WALLET_PRIORITY)
const { data, refetch } = useQuery(WALLETS,
SSR ? {} : { nextFetchPolicy: 'cache-and-network' })
// refetch wallets when the vault key hash changes or wallets are updated
useEffect(() => {
if (me?.privates?.walletsUpdatedAt) {
refetch()
@ -77,9 +80,26 @@ export function WalletsProvider ({ children }) {
.map(w => ({ ...w, status: w.config?.enabled ? Status.Enabled : Status.Disabled }))
}, [data?.wallets, localWallets])
const setPriorities = useCallback(async (priorities) => {
for (const { wallet, priority } of priorities) {
if (!isConfigured(wallet)) {
throw new Error(`cannot set priority for unconfigured wallet: ${wallet.def.name}`)
}
if (wallet.config?.id) {
await setWalletPriority({ variables: { id: wallet.config.id, priority } })
} else {
const storageKey = getStorageKey(wallet.def.name, me?.id)
const config = window.localStorage.getItem(storageKey)
const newConfig = { ...JSON.parse(config), priority }
window.localStorage.setItem(storageKey, JSON.stringify(newConfig))
}
}
}, [setWalletPriority, me?.id])
// provides priority sorted wallets to children
return (
<WalletsContext.Provider value={{ wallets, reloadLocalWallets }}>
<WalletsContext.Provider value={{ wallets, reloadLocalWallets, setPriorities }}>
{children}
</WalletsContext.Provider>
)