Skip to content

Commit d8c6ea3

Browse files
authored
fix: swaps UI (#2336)
1 parent 498142a commit d8c6ea3

File tree

6 files changed

+128
-78
lines changed

6 files changed

+128
-78
lines changed

apps/namadillo/src/App/Common/SelectAssetModal.tsx

Lines changed: 90 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,65 +36,108 @@ export const SelectAssetModal = ({
3636

3737
const [filter, setFilter] = useState("");
3838

39-
const filteredAssets = useMemo(() => {
40-
return assets.filter(
39+
const { assetsWithBalance, assetsWithoutBalance } = useMemo(() => {
40+
const filtered = assets.filter(
4141
(asset) =>
4242
asset.name.toLowerCase().indexOf(filter.toLowerCase()) >= 0 ||
4343
asset.symbol.toLowerCase().indexOf(filter.toLowerCase()) >= 0
4444
);
45-
}, [assets, filter]);
45+
46+
const withBalance: Asset[] = [];
47+
const withoutBalance: Asset[] = [];
48+
49+
filtered.forEach((asset) => {
50+
const tokenAddress =
51+
ibcTransfer === "deposit" ? asset.base : (asset as NamadaAsset).address;
52+
53+
const balance = balances?.[tokenAddress];
54+
const hasBalance = balance && balance[0].gt(0);
55+
56+
if (hasBalance) {
57+
withBalance.push(asset);
58+
} else {
59+
withoutBalance.push(asset);
60+
}
61+
});
62+
63+
return {
64+
assetsWithBalance: withBalance,
65+
assetsWithoutBalance: withoutBalance,
66+
};
67+
}, [assets, filter, balances, ibcTransfer]);
68+
69+
const renderAssetItem = (asset: Asset): JSX.Element => {
70+
// Fpr IbcTransfer(Deposits), we consider base denom as a token address.
71+
const tokenAddress =
72+
ibcTransfer === "deposit" ? asset.base : (asset as NamadaAsset).address;
73+
74+
const disabled =
75+
!namTransfersEnabled && asset.address === nativeTokenAddress;
76+
77+
return (
78+
<li key={asset.base} className="text-sm">
79+
<button
80+
onClick={() => {
81+
onSelect(tokenAddress);
82+
onClose();
83+
}}
84+
className={twMerge(
85+
clsx(
86+
"text-left px-4 py-2.5",
87+
"w-full rounded-sm border border-transparent",
88+
"hover:border-neutral-400 transition-colors duration-150",
89+
{ "pointer-events-none opacity-50": disabled }
90+
)
91+
)}
92+
disabled={disabled}
93+
>
94+
<TokenCard
95+
asset={asset}
96+
address={tokenAddress}
97+
disabled={disabled}
98+
balance={balances?.[tokenAddress]}
99+
/>
100+
</button>
101+
</li>
102+
);
103+
};
104+
105+
const hasAnyAssets =
106+
assetsWithBalance.length > 0 || assetsWithoutBalance.length > 0;
46107

47108
return (
48109
<SelectModal title="Select Asset" onClose={onClose}>
49110
<ConnectedWalletInfo walletAddress={walletAddress} />
50111
<div className="my-4">
51112
<Search placeholder="Search asset" onChange={setFilter} />
52113
</div>
53-
<Stack
54-
as="ul"
55-
gap={0}
56-
className="max-h-[400px] overflow-auto dark-scrollbar pb-4 mr-[-0.5rem]"
57-
>
58-
{filteredAssets.map((asset) => {
59-
// Fpr IbcTransfer(Deposits), we consider base denom as a token address.
60-
const tokenAddress =
61-
ibcTransfer === "deposit" ?
62-
asset.base
63-
: (asset as NamadaAsset).address;
64-
65-
const disabled =
66-
!namTransfersEnabled && asset.address === nativeTokenAddress;
67-
return (
68-
<li key={asset.base} className="text-sm">
69-
<button
70-
onClick={() => {
71-
onSelect(tokenAddress);
72-
onClose();
73-
}}
74-
className={twMerge(
75-
clsx(
76-
"text-left px-4 py-2.5",
77-
"w-full rounded-sm border border-transparent",
78-
"hover:border-neutral-400 transition-colors duration-150",
79-
{ "pointer-events-none opacity-50": disabled }
80-
)
81-
)}
82-
disabled={disabled}
83-
>
84-
<TokenCard
85-
asset={asset}
86-
address={tokenAddress}
87-
disabled={disabled}
88-
balance={balances?.[tokenAddress]}
89-
/>
90-
</button>
91-
</li>
92-
);
93-
})}
94-
{filteredAssets.length === 0 && (
95-
<p className="py-2 font-light">There are no available assets</p>
114+
<div className="max-h-[400px] overflow-auto dark-scrollbar pb-4 mr-[-0.5rem]">
115+
{assetsWithBalance.length > 0 && (
116+
<>
117+
<h3 className="text-xs font-medium text-neutral-500 px-4 py-2 uppercase tracking-wide">
118+
Your tokens
119+
</h3>
120+
<Stack as="ul" gap={0}>
121+
{assetsWithBalance.map(renderAssetItem)}
122+
</Stack>
123+
</>
124+
)}
125+
126+
{assetsWithoutBalance.length > 0 && (
127+
<>
128+
<h3 className="text-xs font-medium text-neutral-500 px-4 py-2 mt-4 uppercase tracking-wide">
129+
All tokens
130+
</h3>
131+
<Stack as="ul" gap={0}>
132+
{assetsWithoutBalance.map(renderAssetItem)}
133+
</Stack>
134+
</>
96135
)}
97-
</Stack>
136+
137+
{!hasAnyAssets && (
138+
<p className="py-2 px-4 font-light">There are no available assets</p>
139+
)}
140+
</div>
98141
</SelectModal>
99142
);
100143
};

apps/namadillo/src/App/Common/SelectedAsset.tsx

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SkeletonLoading, Tooltip } from "@namada/components";
1+
import { SkeletonLoading } from "@namada/components";
22
import { EmptyResourceIcon } from "App/Transfer/EmptyResourceIcon";
33
import clsx from "clsx";
44
import { getAssetImageUrl } from "integrations/utils";
@@ -8,13 +8,15 @@ import { Asset } from "types";
88
type SelectedAssetProps = {
99
asset?: Asset;
1010
isLoading?: boolean;
11+
imageSize?: "small" | "large";
1112
isDisabled?: boolean;
1213
onClick?: () => void;
1314
};
1415

1516
export const SelectedAsset = ({
1617
asset,
1718
isLoading,
19+
imageSize = "small",
1820
isDisabled,
1921
onClick,
2022
}: SelectedAssetProps): JSX.Element => {
@@ -53,29 +55,25 @@ export const SelectedAsset = ({
5355
</span>
5456
)}
5557
{asset && (
56-
<div className="relative group/tooltip">
57-
<Tooltip position="top" className="z-50">
58-
{asset.address}
59-
</Tooltip>
60-
<span className={selectorClassList}>
61-
<img
62-
className={clsx(
63-
"w-8 aspect-square object-cover select-none",
64-
"object-center bg-neutral-800 rounded-full"
65-
)}
66-
alt={`${asset.name} image`}
67-
src={getAssetImageUrl(asset)}
68-
/>
69-
<span className="flex items-center gap-1 text-md">
70-
{asset.symbol}
71-
{!isDisabled && (
72-
<i className="text-sm">
73-
<GoChevronDown />
74-
</i>
75-
)}
76-
</span>
58+
<span className={selectorClassList}>
59+
<img
60+
className={clsx(
61+
imageSize === "small" ? "w-8" : "w-16",
62+
"aspect-square object-cover select-none",
63+
"object-center bg-neutral-800 rounded-full"
64+
)}
65+
alt={`${asset.name} image`}
66+
src={getAssetImageUrl(asset)}
67+
/>
68+
<span className="flex items-center gap-1 text-md">
69+
{asset.symbol}
70+
{!isDisabled && (
71+
<i className="text-sm">
72+
<GoChevronDown />
73+
</i>
74+
)}
7775
</span>
78-
</div>
76+
</span>
7977
)}
8078
</button>
8179
);
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
import { SwapIcon } from "App/Icons/SwapIcon";
2-
31
export const SwapHeader = (): JSX.Element => {
42
return (
53
<header className="flex flex-col items-center text-center mb-8 gap-5">
64
<h1 className="text-yellow"> Shielded Swaps </h1>
7-
<i className="flex items-center justify-center w-13 text-yellow mx-auto relative z-10">
8-
<SwapIcon />
9-
</i>
10-
<p>Swap an asset you hold in the shield pool</p>
115
</header>
126
);
137
};

apps/namadillo/src/App/Swap/SwapModule.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Panel } from "@namada/components";
2+
import { MaspSyncCover } from "App/Common/MaspSyncCover";
3+
import { useRequiresNewShieldedSync } from "hooks/useRequiresNewShieldedSync";
24
import { useAtomValue } from "jotai";
35
import { Link } from "react-router-dom";
46
import { swapStatusAtom } from "./state/atoms";
@@ -12,6 +14,7 @@ import { SwapSuccess } from "./SwapSuccess";
1214
// and pass the shared state(accounts, fees, etc.) as props to the module components
1315
export const SwapModule = (): JSX.Element => {
1416
const status = useAtomValue(swapStatusAtom);
17+
const requiresNewShieldedSync = useRequiresNewShieldedSync();
1518

1619
return (
1720
<Panel className="relative rounded-sm flex flex-col flex-1 pt-9">
@@ -44,6 +47,7 @@ export const SwapModule = (): JSX.Element => {
4447
</p>
4548
)}
4649
</section>
50+
{requiresNewShieldedSync && <MaspSyncCover />}
4751
</Panel>
4852
);
4953
};

apps/namadillo/src/App/Swap/SwapSource.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const SwapSource = ({
4141
{!isSubmitting && (
4242
<div className="grid grid-cols-[max-content_auto] gap-5 mb-3">
4343
<SelectedAsset
44+
imageSize="large"
4445
asset={asset}
4546
isLoading={isLoadingAssets}
4647
onClick={openAssetSelector}

apps/namadillo/src/App/Transactions/LocalStorageTransactionCard.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,19 @@ export const LocalStorageTransactionCard = ({
201201
<h4 className="text-neutral-400">To</h4>
202202
<div className="flex items-center justify-between">
203203
<h4
204-
className={isShieldedAddress(receiver ?? "") ? "text-yellow" : ""}
204+
className={
205+
(
206+
isShieldedAddress(receiver ?? "") ||
207+
transaction.type === "ShieldedOsmosisSwap"
208+
) ?
209+
"text-yellow"
210+
: ""
211+
}
205212
>
206-
{isShieldedAddress(receiver ?? "") ?
213+
{(
214+
isShieldedAddress(receiver ?? "") ||
215+
transaction.type === "ShieldedOsmosisSwap"
216+
) ?
207217
<span className="flex items-center gap-1">
208218
<FaLock className="w-4 h-4" /> Shielded
209219
</span>

0 commit comments

Comments
 (0)