Skip to content

Commit 23bb767

Browse files
authored
Merge pull request #499 from pandablue0809/feat/459/change-endpoint-token-selector
bug in the token select on /send page
2 parents 4ccd49d + 6898a8a commit 23bb767

File tree

2 files changed

+61
-117
lines changed

2 files changed

+61
-117
lines changed

components/UI/TokenSelector.js

Lines changed: 60 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,50 @@ import { IoSearch } from 'react-icons/io5'
44
import { IoMdClose } from 'react-icons/io'
55
import { IoChevronDown } from 'react-icons/io5'
66
import axios from 'axios'
7-
import {
8-
avatarServer,
9-
nativeCurrency,
10-
isNativeCurrency,
11-
nativeCurrenciesImages,
12-
useWidth,
13-
setTabParams
14-
} from '../../utils'
15-
import { niceCurrency, shortAddress, shortNiceNumber, amountFormat } from '../../utils/format'
7+
import { nativeCurrency, nativeCurrenciesImages, useWidth, setTabParams, tokenImageSrc } from '../../utils'
8+
import { niceCurrency, shortAddress, shortNiceNumber } from '../../utils/format'
169
import RadioOptions from './RadioOptions'
1710
import { useRouter } from 'next/router'
1811

1912
const limit = 20
2013

2114
// Helper function to fetch and process trustlines for a destination address
2215
const fetchTrustlinesForDestination = async (destinationAddress, searchQuery = '') => {
23-
const response = await axios(`v2/objects/${destinationAddress}?limit=1000&type=state`)
24-
const objects = response.data?.objects || []
16+
const response = await axios(`v2/address/${destinationAddress}/acceptedTokens?limit=${limit}`)
17+
const tokens = response.data?.tokens || []
2518

26-
// Filter RippleState objects to get trustlines where destination can hold tokens
27-
const trustlines = objects.filter((obj) => {
28-
if (parseFloat(obj.LowLimit.value) <= 0 && parseFloat(obj.HighLimit.value) <= 0) return false
19+
// Trim the search query to handle whitespace
20+
const trimmedQuery = searchQuery.trim()
2921

22+
const trustlines = tokens.filter((token) => {
3023
// If search query is provided, filter by it
31-
if (searchQuery) {
32-
const currency = obj.Balance.currency
33-
const issuerDetails =
34-
obj.HighLimit.issuer === destinationAddress ? obj.LowLimit.issuerDetails : obj.HighLimit.issuerDetails || {}
35-
const serviceOrUsername = issuerDetails.service || issuerDetails.username || ''
36-
const issuer = obj.HighLimit.issuer === destinationAddress ? obj.LowLimit.issuer : obj.HighLimit.issuer || ''
37-
38-
const searchLower = searchQuery.toLowerCase()
24+
if (trimmedQuery) {
25+
const currency = token.currency
26+
const issuerDetails = token.issuerDetails || {}
27+
const service = issuerDetails.service || ''
28+
const username = issuerDetails.username || ''
29+
const issuer = token.issuer || ''
30+
31+
const searchLower = trimmedQuery.toLowerCase()
3932
return (
4033
currency.toLowerCase().includes(searchLower) ||
41-
serviceOrUsername.toLowerCase().includes(searchLower) ||
34+
service.toLowerCase().includes(searchLower) ||
35+
username.toLowerCase().includes(searchLower) ||
4236
issuer.toLowerCase().includes(searchLower)
4337
)
4438
}
45-
4639
return true
4740
})
4841

49-
// Convert trustlines to token format
50-
return trustlines.map((tl) => ({
51-
currency: tl.Balance.currency,
52-
issuer: tl.HighLimit.issuer === destinationAddress ? tl.LowLimit.issuer : tl.HighLimit.issuer,
53-
issuerDetails: tl.HighLimit.issuer === destinationAddress ? tl.LowLimit.issuerDetails : tl.HighLimit.issuerDetails,
54-
limit: Math.max(parseFloat(tl.LowLimit.value), parseFloat(tl.HighLimit.value)),
55-
balance: tl.Balance.value
56-
}))
42+
return trustlines
5743
}
5844

5945
// Helper function to add native currency to tokens array if needed
6046
const addNativeCurrencyIfNeeded = (tokens, excludeNative, searchQuery = '') => {
6147
if (excludeNative) return tokens
6248

63-
const shouldAddNative = !searchQuery || searchQuery.toUpperCase() === nativeCurrency.toUpperCase()
49+
const trimmedQuery = searchQuery.trim()
50+
const shouldAddNative = !trimmedQuery || trimmedQuery.toUpperCase() === nativeCurrency.toUpperCase()
6451
if (shouldAddNative) {
6552
tokens.unshift({ currency: nativeCurrency, limit: null })
6653
}
@@ -85,6 +72,10 @@ export default function TokenSelector({
8572
const [isLoading, setIsLoading] = useState(false)
8673
const [searchTimeout, setSearchTimeout] = useState(null)
8774

75+
// Cache for search results to prevent unnecessary reloads
76+
const [lastSearchQuery, setLastSearchQuery] = useState('')
77+
const [cachedSearchResults, setCachedSearchResults] = useState([])
78+
8879
// control radio selection: 'all' | 'single'
8980
const [filterMode, setFilterMode] = useState(() => (value?.currency ? 'single' : 'all'))
9081

@@ -120,6 +111,8 @@ export default function TokenSelector({
120111
useEffect(() => {
121112
setSearchResults([])
122113
setSearchQuery('')
114+
setLastSearchQuery('')
115+
setCachedSearchResults([])
123116
}, [destinationAddress])
124117

125118
// Handle search with debounce
@@ -133,23 +126,11 @@ export default function TokenSelector({
133126
}
134127

135128
const timeout = setTimeout(async () => {
136-
if (!searchQuery) {
137-
// Only apply the early return logic when there's no destination address
138-
// When destination address is provided, we always want to fetch fresh data
139-
if (!destinationAddress) {
140-
// do not reload default token list if it's already loaded
141-
// when searched for native currency, we also add the native currency on top,
142-
// so check that it's not that case before canceling the search
143-
if (
144-
isNativeCurrency(searchResults[0]) &&
145-
!niceCurrency(searchResults[1]?.currency)?.toLowerCase().startsWith(nativeCurrency.toLowerCase())
146-
)
147-
return
148-
} else {
149-
// For destination address case, check if we already have results loaded
150-
if (searchResults.length > 0) {
151-
return
152-
}
129+
if (!searchQuery.trim()) {
130+
// Check if we have cached results for empty search query
131+
if (lastSearchQuery === '' && cachedSearchResults.length > 0) {
132+
setSearchResults(cachedSearchResults)
133+
return
153134
}
154135

155136
setIsLoading(true)
@@ -159,51 +140,77 @@ export default function TokenSelector({
159140
if (destinationAddress) {
160141
// Fetch tokens that destination can hold based on trustlines
161142
tokens = await fetchTrustlinesForDestination(destinationAddress)
162-
tokens = addNativeCurrencyIfNeeded(tokens, excludeNative)
163143
} else {
164144
// Fallback to original behavior if no destination address
165145
const response = await axios('v2/trustlines/tokens?limit=' + limit + '&currencyDetails=true')
166146
tokens = response.data?.tokens || []
167147
if (!excludeNative) {
168-
setSearchResults([{ currency: nativeCurrency }, ...tokens])
148+
const defaultTokens = [{ currency: nativeCurrency }, ...tokens]
149+
setSearchResults(defaultTokens)
150+
// Cache the default token list
151+
setLastSearchQuery('')
152+
setCachedSearchResults(defaultTokens)
169153
} else {
170154
setSearchResults(tokens)
155+
// Cache the default token list
156+
setLastSearchQuery('')
157+
setCachedSearchResults(tokens)
171158
}
172159
setIsLoading(false)
173160
return
174161
}
175162

176163
setSearchResults(tokens)
164+
// Cache the default token list for destination address case
165+
setLastSearchQuery('')
166+
setCachedSearchResults(tokens)
177167
} catch (error) {
178168
console.error('Error loading tokens:', error)
179169
if (excludeNative) {
180170
setSearchResults([])
171+
setLastSearchQuery('')
172+
setCachedSearchResults([])
181173
} else {
182174
setSearchResults([{ currency: nativeCurrency }])
175+
setLastSearchQuery('')
176+
setCachedSearchResults([{ currency: nativeCurrency }])
183177
}
184178
} finally {
185179
setIsLoading(false)
186180
}
187181
return
188182
}
189183

184+
// Check if we have cached results for this search query
185+
if (lastSearchQuery === searchQuery) {
186+
setSearchResults(cachedSearchResults)
187+
return
188+
}
189+
190190
setIsLoading(true)
191191
try {
192192
if (destinationAddress) {
193193
// For destination-specific search, filter the existing trustlines
194194
const tokens = await fetchTrustlinesForDestination(destinationAddress, searchQuery)
195195
const tokensWithNative = addNativeCurrencyIfNeeded(tokens, excludeNative, searchQuery)
196196
setSearchResults(tokensWithNative)
197+
// Cache the results
198+
setLastSearchQuery(searchQuery)
199+
setCachedSearchResults(tokensWithNative)
197200
} else {
198201
// Fallback to original search behavior
199202
const response = await axios(`v2/trustlines/tokens/search/${searchQuery}?limit=${limit}&currencyDetails=true`)
200203
const tokens = response.data?.tokens || []
201204
const tokensWithNative = addNativeCurrencyIfNeeded(tokens, excludeNative, searchQuery)
202205
setSearchResults(tokensWithNative)
206+
// Cache the results
207+
setLastSearchQuery(searchQuery)
208+
setCachedSearchResults(tokensWithNative)
203209
}
204210
} catch (error) {
205211
console.error('Error searching tokens:', error)
206212
setSearchResults([])
213+
setCachedSearchResults([])
207214
} finally {
208215
setIsLoading(false)
209216
}
@@ -222,12 +229,11 @@ export default function TokenSelector({
222229
const handleSelect = (token) => {
223230
onChange(token)
224231
setIsOpen(false)
225-
setSearchQuery('')
226232
}
227233

228234
// Helper to get icon url if available
229235
const getTokenIcon = (token) => {
230-
let imageUrl = avatarServer + token.issuer
236+
let imageUrl = tokenImageSrc(token)
231237
if (!token.issuer) {
232238
imageUrl = nativeCurrenciesImages[nativeCurrency]
233239
}
@@ -250,20 +256,6 @@ export default function TokenSelector({
250256
return niceCurrency(token.currency)
251257
}
252258

253-
// Helper to get token limit display
254-
const getTokenLimitDisplay = (token) => {
255-
if (!token.limit || token.currency === nativeCurrency) return null
256-
257-
return (
258-
<div className="token-selector-modal-item-limit">
259-
<span className="token-selector-modal-item-limit-label">Max:</span>
260-
<span className="token-selector-modal-item-limit-value">
261-
{amountFormat({ value: token.limit, currency: token.currency, issuer: token.issuer }, { short: true })}
262-
</span>
263-
</div>
264-
)
265-
}
266-
267259
return (
268260
<>
269261
{allOrOne && (
@@ -373,7 +365,6 @@ export default function TokenSelector({
373365
)}
374366
</span>
375367
{width > 1100 ? <span>{token.issuer}</span> : <span>{shortAddress(token.issuer)}</span>}
376-
{getTokenLimitDisplay(token)}
377368
</div>
378369
</div>
379370
</div>

pages/services/send.js

Lines changed: 1 addition & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -99,53 +99,6 @@ export default function Send({
9999
setSelectedToken(token)
100100
}
101101

102-
// Helper to get maximum amount that can be sent for the selected token
103-
const getMaxAmount = () => {
104-
if (!selectedToken || selectedToken.currency === nativeCurrency) return null
105-
return selectedToken.limit
106-
}
107-
108-
// Helper to format max amount display
109-
const getMaxAmountDisplay = () => {
110-
const maxAmount = getMaxAmount()
111-
if (!maxAmount) return null
112-
113-
return (
114-
<>
115-
<span className="max-amount-display">
116-
(<span className="max-amount-label">Dest. can accept max</span>{' '}
117-
<span className="max-amount-value">
118-
{amountFormat(
119-
{ value: maxAmount, currency: selectedToken.currency, issuer: selectedToken.issuer },
120-
{ short: true }
121-
)}
122-
</span>
123-
)
124-
</span>
125-
<style jsx>{`
126-
.max-amount-display {
127-
align-items: center;
128-
margin-top: 4px;
129-
font-size: 12px;
130-
131-
.max-amount-label {
132-
color: #6b7280;
133-
font-weight: 500;
134-
.dark & {
135-
color: #9ca3af;
136-
}
137-
}
138-
139-
.max-amount-value {
140-
color: var(--accent-link);
141-
font-weight: 500;
142-
}
143-
}
144-
`}</style>
145-
</>
146-
)
147-
}
148-
149102
// Fetch network info for reserve amounts only when account is not activated
150103
useEffect(() => {
151104
const fetchNetworkInfo = async () => {
@@ -532,7 +485,7 @@ export default function Send({
532485
<FormInput
533486
title={
534487
<>
535-
{t('table.amount')} {getMaxAmountDisplay()}
488+
{t('table.amount')}
536489
</>
537490
}
538491
placeholder="Enter amount"

0 commit comments

Comments
 (0)