11import { RowSelectionState , SortingState } from '@tanstack/react-table'
2- import { useCallback , useEffect , useMemo , useState } from 'react'
2+ import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
33
44import { Callout , CalloutType } from 'components/common/Callout'
55import Table from 'components/common/Table'
66import Text from 'components/common/Text'
77import useAssetSelectColumns from 'components/Modals/AssetsSelect/Columns/useAssetSelectColumns'
8- import useWhitelistedAssets from 'hooks/assets/useWhitelistedAssets'
98import useMarkets from 'hooks/markets/useMarkets'
109import useStore from 'store'
1110import { BNCoin } from 'types/classes/BNCoin'
11+ import { byDenom } from 'utils/array'
1212import { getCoinValue } from 'utils/formatters'
1313import { BN } from 'utils/helpers'
14- import { byDenom } from 'utils/array'
1514
1615interface Props {
1716 assets : Asset [ ]
@@ -53,30 +52,16 @@ export default function AssetsSelect(props: Props) {
5352 } , [ columns , hideColumns ] )
5453
5554 const markets = useMarkets ( )
56- const whitelistedAssets = useWhitelistedAssets ( )
5755 const walletBalances = useStore ( ( s ) => s . balances )
58- const filteredWhitelistedAsset = useMemo (
59- ( ) => whitelistedAssets . filter ( ( asset ) => ! asset . isDeprecated ) ,
60- [ whitelistedAssets ] ,
61- )
6256
6357 const [ sorting , setSorting ] = useState < SortingState > ( [
6458 { id : isBorrow ? 'asset.borrowRate' : 'value' , desc : ! isBorrow } ,
6559 ] )
6660
6761 const defaultSelected = useMemo ( ( ) => {
68- return assets . reduce (
69- ( acc , asset , index ) => {
70- const assetIdentifier = asset . chainName ? `${ asset . denom } :${ asset . chainName } ` : asset . denom
71-
72- if ( selectedDenoms ?. includes ( assetIdentifier ) ) {
73- acc [ index ] = true
74- }
75- return acc
76- } ,
77- { } as { [ key : number ] : boolean } ,
78- )
79- } , [ selectedDenoms , assets ] )
62+ // Don't initialize here - let the effect handle it based on actual tableData
63+ return { }
64+ } , [ ] )
8065
8166 const createTableData = useCallback (
8267 ( assets : Asset [ ] ) : AssetTableRow [ ] => {
@@ -138,81 +123,125 @@ export default function AssetsSelect(props: Props) {
138123 return depositBalance . plus ( lendBalance ) . isGreaterThan ( 0 )
139124 } )
140125 } else {
141- const whitelistedTableData = filteredWhitelistedAsset . filter ( ( asset ) =>
142- walletBalances . some ( ( balance ) => balance . denom === asset . denom && balance . amount !== '0' ) ,
126+ // Filter assets based on wallet balances, matching both denom and chainName
127+ filteredAssets = assets . filter ( ( asset ) =>
128+ walletBalances . some (
129+ ( balance ) =>
130+ balance . denom === asset . denom &&
131+ balance . chainName === asset . chainName &&
132+ balance . amount !== '0' ,
133+ ) ,
143134 )
144- filteredAssets = whitelistedTableData
145135 }
146136
147137 const whitelistedData = createTableData ( filteredAssets )
148138 const nonCollateralData = createTableData ( filteredNonCollateralAssets )
149139
150140 return { whitelistedData, nonCollateralData }
151- } , [
152- assets ,
153- nonCollateralTableAssets ,
154- filteredWhitelistedAsset ,
155- walletBalances ,
156- createTableData ,
157- account ,
158- repayFromWallet ,
159- ] )
141+ } , [ assets , nonCollateralTableAssets , walletBalances , createTableData , account , repayFromWallet ] )
160142
161- const [ whitelistedSelected , setWhitelistedSelected ] = useState < RowSelectionState > ( defaultSelected )
162- const [ nonCollateralSelected , setNonCollateralSelected ] = useState < RowSelectionState > (
163- nonCollateralTableAssets ?. reduce ( ( acc , _ , index ) => {
164- const assetIdentifier = nonCollateralTableAssets [ index ] . chainName
165- ? `${ nonCollateralTableAssets [ index ] . denom } :${ nonCollateralTableAssets [ index ] . chainName } `
166- : nonCollateralTableAssets [ index ] . denom
143+ const [ whitelistedSelected , setWhitelistedSelected ] = useState < RowSelectionState > ( { } )
144+ const [ nonCollateralSelected , setNonCollateralSelected ] = useState < RowSelectionState > ( { } )
167145
168- acc [ index ] = selectedDenoms ?. includes ( assetIdentifier ) || false
169- return acc
170- } , { } as RowSelectionState ) ?? { } ,
171- )
146+ // Track table data identity to detect when table structure changes (not just values)
147+ const tableDataIdentity = useMemo ( ( ) => {
148+ const data = Array . isArray ( tableData ) ? tableData : tableData . whitelistedData || [ ]
149+ const nonCollateral = Array . isArray ( tableData ) ? [ ] : tableData . nonCollateralData || [ ]
150+ return (
151+ data . map ( ( row ) => `${ row . asset . denom } :${ row . asset . chainName || '' } ` ) . join ( ',' ) +
152+ '|' +
153+ nonCollateral . map ( ( row ) => `${ row . asset . denom } :${ row . asset . chainName || '' } ` ) . join ( ',' )
154+ )
155+ } , [ tableData ] )
156+
157+ const prevTableIdentityRef = useRef < string > ( '' )
158+
159+ // Sync selection from selectedDenoms only when table structure changes
160+ useEffect ( ( ) => {
161+ // Check if table structure changed (or initial mount)
162+ if ( prevTableIdentityRef . current !== tableDataIdentity ) {
163+ prevTableIdentityRef . current = tableDataIdentity
164+
165+ // Initialize selection state based on selectedDenoms and current tableData
166+ if ( Array . isArray ( tableData ) ) {
167+ const selection : RowSelectionState = { }
168+ tableData . forEach ( ( row , index ) => {
169+ const assetIdentifier = row . asset . chainName
170+ ? `${ row . asset . denom } :${ row . asset . chainName } `
171+ : row . asset . denom
172+ if ( selectedDenoms ?. includes ( assetIdentifier ) ) {
173+ selection [ index ] = true
174+ }
175+ } )
176+ setWhitelistedSelected ( selection )
177+ setNonCollateralSelected ( { } )
178+ } else {
179+ const whitelistedSelection : RowSelectionState = { }
180+ const nonCollateralSelection : RowSelectionState = { }
181+
182+ tableData . whitelistedData ?. forEach ( ( row , index ) => {
183+ const assetIdentifier = row . asset . chainName
184+ ? `${ row . asset . denom } :${ row . asset . chainName } `
185+ : row . asset . denom
186+ if ( selectedDenoms ?. includes ( assetIdentifier ) ) {
187+ whitelistedSelection [ index ] = true
188+ }
189+ } )
190+
191+ tableData . nonCollateralData ?. forEach ( ( row , index ) => {
192+ const assetIdentifier = row . asset . chainName
193+ ? `${ row . asset . denom } :${ row . asset . chainName } `
194+ : row . asset . denom
195+ if ( selectedDenoms ?. includes ( assetIdentifier ) ) {
196+ nonCollateralSelection [ index ] = true
197+ }
198+ } )
199+
200+ setWhitelistedSelected ( whitelistedSelection )
201+ setNonCollateralSelected ( nonCollateralSelection )
202+ }
203+ }
204+ } , [ tableDataIdentity , tableData , selectedDenoms ] )
172205
206+ // Notify parent when selection changes
173207 useEffect ( ( ) => {
174- let newSelectedDenoms : string [ ]
208+ let selectedAssets : Asset [ ] = [ ]
175209
176210 if ( Array . isArray ( tableData ) ) {
177- const selectedAssets = assets . filter ( ( asset , idx ) => whitelistedSelected [ idx ] )
178-
179- newSelectedDenoms = selectedAssets . map ( ( asset ) =>
180- asset . chainName ? `${ asset . denom } :${ asset . chainName } ` : asset . denom ,
181- )
211+ // Simple case: just get selected assets from the table
212+ selectedAssets = tableData
213+ . filter ( ( _ , idx ) => whitelistedSelected [ idx ] )
214+ . map ( ( row ) => row . asset )
182215 } else {
183- const filteredWhitelistedAsset = assets . filter ( ( asset , index ) => whitelistedSelected [ index ] )
184- const nonCollateralAssets =
185- nonCollateralTableAssets ?. filter ( ( _ , index ) => nonCollateralSelected [ index ] ) || [ ]
216+ // Two-table case: combine selections from both tables
217+ const whitelistedTableData = tableData . whitelistedData || [ ]
218+ const nonCollateralTableData = tableData . nonCollateralData || [ ]
186219
187- const allSelectedAssets = [ ...filteredWhitelistedAsset , ...nonCollateralAssets ]
220+ const selectedWhitelistedAssets = whitelistedTableData
221+ . filter ( ( _ , index ) => whitelistedSelected [ index ] )
222+ . map ( ( row ) => row . asset )
188223
189- const debtAsset = allSelectedAssets . find ( ( asset ) => asset . denom === assets [ 0 ] ?. denom )
190- const swapAsset = allSelectedAssets . find ( ( asset ) => asset . denom !== assets [ 0 ] ?. denom )
224+ const selectedNonCollateralAssets = nonCollateralTableData
225+ . filter ( ( _ , index ) => nonCollateralSelected [ index ] )
226+ . map ( ( row ) => row . asset )
191227
192- const finalSelectedAssets = [ debtAsset , swapAsset ] . filter ( Boolean ) as Asset [ ]
193-
194- newSelectedDenoms = finalSelectedAssets
195- . sort ( ( a , b ) => a . symbol . localeCompare ( b . symbol ) )
196- . map ( ( asset ) => ( asset . chainName ? `${ asset . denom } :${ asset . chainName } ` : asset . denom ) )
228+ selectedAssets = [ ...selectedWhitelistedAssets , ...selectedNonCollateralAssets ]
197229 }
198230
199- if (
200- selectedDenoms . length === newSelectedDenoms . length &&
201- newSelectedDenoms . every ( ( denom ) => selectedDenoms . includes ( denom ) )
202- ) {
203- return
204- }
231+ // Convert to denom strings with optional chain names
232+ const newSelectedDenoms = selectedAssets . map ( ( asset ) =>
233+ asset . chainName ? `${ asset . denom } :${ asset . chainName } ` : asset . denom ,
234+ )
205235
206- onChangeSelected ( newSelectedDenoms )
207- } , [
208- whitelistedSelected ,
209- nonCollateralSelected ,
210- tableData ,
211- assets ,
212- selectedDenoms ,
213- onChangeSelected ,
214- nonCollateralTableAssets ,
215- ] )
236+ // Only call onChangeSelected if the selection actually changed to avoid infinite loops
237+ const hasChanged =
238+ selectedDenoms . length !== newSelectedDenoms . length ||
239+ ! newSelectedDenoms . every ( ( denom ) => selectedDenoms . includes ( denom ) )
240+
241+ if ( hasChanged ) {
242+ onChangeSelected ( newSelectedDenoms )
243+ }
244+ } , [ whitelistedSelected , nonCollateralSelected , tableData , onChangeSelected , selectedDenoms ] )
216245
217246 const handleNonCollateralSelection : (
218247 updaterOrValue : RowSelectionState | ( ( old : RowSelectionState ) => RowSelectionState ) ,
@@ -246,13 +275,16 @@ export default function AssetsSelect(props: Props) {
246275 )
247276 }
248277
278+ const whitelistedData = ! Array . isArray ( tableData ) ? tableData . whitelistedData : [ ]
279+ const nonCollateralData = ! Array . isArray ( tableData ) ? tableData . nonCollateralData : [ ]
280+
249281 return (
250282 < >
251- { ( nonCollateralTableAssets . length > 0 || assets . length > 0 ) && (
283+ { ( nonCollateralData . length > 0 || whitelistedData . length > 0 ) && (
252284 < Table
253285 title = { assetsSectionTitle }
254286 columns = { columns }
255- data = { createTableData ( assets ) }
287+ data = { whitelistedData }
256288 initialSorting = { sorting }
257289 onSortingChange = { setSorting }
258290 setRowSelection = { setWhitelistedSelected }
@@ -269,23 +301,23 @@ export default function AssetsSelect(props: Props) {
269301 />
270302 ) }
271303
272- { nonCollateralTableAssets . length === 0 && assets . length === 0 && (
304+ { nonCollateralData . length === 0 && whitelistedData . length === 0 && (
273305 < Callout type = { CalloutType . INFO } className = 'mx-4 mt-4 text-white/60' >
274306 No assets that match your search.
275307 </ Callout >
276308 ) }
277309
278- { nonCollateralTableAssets . length > 0 && assets . length === 0 && (
310+ { nonCollateralData . length > 0 && whitelistedData . length === 0 && (
279311 < Callout type = { CalloutType . INFO } className = 'm-4 text-white/60' >
280312 No whitelisted assets found in your wallet.
281313 </ Callout >
282314 ) }
283315
284- { nonCollateralTableAssets . length > 0 && (
316+ { nonCollateralData . length > 0 && (
285317 < Table
286318 title = { nonCollateralAssetsSectionTitle }
287319 columns = { columns }
288- data = { createTableData ( nonCollateralTableAssets ) }
320+ data = { nonCollateralData }
289321 initialSorting = { sorting }
290322 onSortingChange = { setSorting }
291323 setRowSelection = { handleNonCollateralSelection }
0 commit comments