Skip to content

Commit fdbe93a

Browse files
authored
Merge pull request #1676 from mars-protocol/develop
v3.0.0
2 parents 0eaecf6 + 5f36d88 commit fdbe93a

File tree

23 files changed

+200
-229
lines changed

23 files changed

+200
-229
lines changed

src/components/Modals/AssetsSelect/index.tsx

Lines changed: 113 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { RowSelectionState, SortingState } from '@tanstack/react-table'
2-
import { useCallback, useEffect, useMemo, useState } from 'react'
2+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
33

44
import { Callout, CalloutType } from 'components/common/Callout'
55
import Table from 'components/common/Table'
66
import Text from 'components/common/Text'
77
import useAssetSelectColumns from 'components/Modals/AssetsSelect/Columns/useAssetSelectColumns'
8-
import useWhitelistedAssets from 'hooks/assets/useWhitelistedAssets'
98
import useMarkets from 'hooks/markets/useMarkets'
109
import useStore from 'store'
1110
import { BNCoin } from 'types/classes/BNCoin'
11+
import { byDenom } from 'utils/array'
1212
import { getCoinValue } from 'utils/formatters'
1313
import { BN } from 'utils/helpers'
14-
import { byDenom } from 'utils/array'
1514

1615
interface 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}

src/components/account/AccountList/AccountStats.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export default function AccountStats(props: Props) {
8888
const navigateToVaultDetails = useCallback(() => {
8989
if (!account) return
9090
setShowMenu?.(false)
91+
useStore.setState({ mobileNavExpanded: false })
9192
const vaultAddress =
9293
typeof account.kind === 'object' && 'fund_manager' in account.kind
9394
? account.kind.fund_manager.vault_addr

src/components/account/AccountList/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ export default function AccountList(props: Props) {
7777
contentClassName='bg-surface group-hover/account:bg-surface'
7878
onClick={() => {
7979
if (isActive) return
80-
if (isMobile) setShowMenu(false)
80+
if (isMobile) {
81+
setShowMenu(false)
82+
useStore.setState({ mobileNavExpanded: false })
83+
}
8184
useStore.setState({ accountDeleteModal: null })
8285

8386
navigate(

src/components/common/Background.tsx

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/components/common/Card/CardWithTabs.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export function CardWithTabs(props: Props) {
2323
{...props}
2424
/>
2525
}
26-
className='w-full h-full'
27-
contentClassName='flex-1 h-full'
26+
className='w-full md:h-full'
27+
contentClassName='flex-1 md:h-full'
2828
>
2929
{props.tabs[activeIdx].renderContent()}
3030
</Card>

src/components/common/Card/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function Card(props: Props) {
2323
className={classNames(
2424
props.className,
2525
'flex flex-col',
26-
'relative isolate max-w-full max-h-full',
26+
'relative isolate max-w-full md:max-h-full',
2727
!props.showOverflow && 'overflow-hidden',
2828
isTab ? '' : 'bg-surface rounded-sm border border-surface-light',
2929
)}

0 commit comments

Comments
 (0)