Skip to content

Commit ec7dfbf

Browse files
committed
cleans up UI
1 parent 8abf7d6 commit ec7dfbf

File tree

1 file changed

+107
-17
lines changed

1 file changed

+107
-17
lines changed

packages/mobile-app/app/send/index.tsx

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useFacade } from "../../data/facades";
44
import { useState, useMemo } from "react";
55
import { IRON_ASSET_ID_HEX } from "../../data/constants";
66
import { CurrencyUtils } from "@ironfish/sdk";
7-
import { useQueries, useMutation } from "@tanstack/react-query";
7+
import { useQueries } from "@tanstack/react-query";
88
import { Asset } from "@/data/facades/chain/types";
99
import { AccountBalance } from "@/data/facades/wallet/types";
1010
import {
@@ -20,7 +20,6 @@ import {
2020
IndexPath,
2121
IconProps,
2222
Modal,
23-
Spinner,
2423
} from "@ui-kitten/components";
2524
import SendConfirmed from "../../svgs/SendConfirmed";
2625
import Rubics from "../../svgs/Rubics";
@@ -36,19 +35,81 @@ const isValidBigInt = (num: string) => {
3635
}
3736
};
3837

39-
const isValidAmount = (value: string, decimals: number) => {
38+
const convertAmountToMinor = (
39+
amount: string,
40+
assetId: string,
41+
assetMap: Map<string, Asset>,
42+
): [bigint, null] | [null, Error] => {
43+
const asset =
44+
assetId === IRON_ASSET_ID_HEX ? undefined : assetMap.get(assetId);
45+
return CurrencyUtils.tryMajorToMinor(amount, assetId, {
46+
decimals: getAssetDecimals(asset),
47+
});
48+
};
49+
50+
const isValidAmount = (
51+
value: string,
52+
assetId: string,
53+
assetMap: Map<string, Asset>,
54+
) => {
4055
if (value.length === 0) return true;
56+
57+
const asset =
58+
assetId === IRON_ASSET_ID_HEX ? undefined : assetMap.get(assetId);
59+
60+
// For unverified assets, don't allow any decimals
61+
if (asset && asset.verification.status !== "verified") {
62+
return !value.includes(".");
63+
}
64+
65+
const decimals = getAssetDecimals(asset) ?? 8; // $IRON has 8 decimals by default
4166
const parts = value.split(".");
4267
return parts.length <= 2 && (parts[1]?.length ?? 0) <= decimals;
4368
};
4469

70+
const enforceDecimals = (
71+
value: string,
72+
assetId: string,
73+
assetMap: Map<string, Asset>,
74+
): string => {
75+
if (value.length === 0) return value;
76+
77+
const asset =
78+
assetId === IRON_ASSET_ID_HEX ? undefined : assetMap.get(assetId);
79+
80+
// For unverified assets, remove any decimal points
81+
if (asset && asset.verification.status !== "verified") {
82+
return value.replace(/\./g, "");
83+
}
84+
85+
const decimals = getAssetDecimals(asset) ?? 8;
86+
const parts = value.split(".");
87+
if (parts.length === 2 && parts[1].length > decimals) {
88+
return `${parts[0]}.${parts[1].slice(0, decimals)}`;
89+
}
90+
91+
return value;
92+
};
93+
4594
const CheckIcon = (props: IconProps) => (
4695
<Icon {...props} name="checkmark-outline" />
4796
);
4897

4998
// First add a new type for the transaction state
5099
type TransactionState = "sending" | "sent" | "idle";
51100

101+
// Add this helper at the top with other utility functions
102+
const getAssetDecimals = (asset: Asset | undefined): number | undefined => {
103+
if (!asset) return undefined;
104+
try {
105+
return asset.verification.status === "verified"
106+
? asset.verification.decimals
107+
: JSON.parse(asset.metadata).decimals;
108+
} catch {
109+
return undefined;
110+
}
111+
};
112+
52113
export default function Send() {
53114
const facade = useFacade();
54115
const router = useRouter();
@@ -139,16 +200,28 @@ export default function Send() {
139200
);
140201
}, [selectedAssetId, assetOptions]);
141202

142-
const decimals =
143-
selectedAssetId === IRON_ASSET_ID_HEX
144-
? 8
145-
: assetMap.get(selectedAssetId)?.verification.status === "verified"
146-
? (assetMap.get(selectedAssetId)?.verification.decimals ?? 0)
147-
: 0;
148-
149203
// Add the mutation
150204
const sendTransactionMutation = facade.sendTransaction.useMutation();
151205

206+
// Add amount validation
207+
const amountError = useMemo(() => {
208+
if (!amount) return undefined;
209+
210+
if (!isValidAmount(amount, selectedAssetId, assetMap)) {
211+
const asset =
212+
selectedAssetId === IRON_ASSET_ID_HEX
213+
? undefined
214+
: assetMap.get(selectedAssetId);
215+
const decimals = getAssetDecimals(asset) ?? 8;
216+
return `Maximum ${decimals} decimal places allowed`;
217+
}
218+
219+
const [amountInMinorUnits] =
220+
convertAmountToMinor(amount, selectedAssetId, assetMap) ?? [];
221+
222+
return undefined;
223+
}, [amount, selectedAssetId, assetMap]);
224+
152225
return (
153226
<Layout style={styles.container} level="1">
154227
<Stack.Screen options={{ headerTitle: "Send Transaction" }} />
@@ -194,13 +267,22 @@ export default function Send() {
194267
placeholder="Enter amount"
195268
value={amount}
196269
onChangeText={(value) => {
197-
if (isValidAmount(value, decimals)) {
198-
setAmount(value);
199-
}
270+
const sanitized = enforceDecimals(value, selectedAssetId, assetMap);
271+
setAmount(sanitized);
200272
}}
201273
style={styles.input}
202-
keyboardType="numeric"
203-
caption={`Maximum ${decimals} decimal places`}
274+
status={amountError ? "danger" : "basic"}
275+
caption={
276+
amountError ||
277+
(assetMap.get(selectedAssetId)?.verification.status === "unverified"
278+
? "No decimals allowed"
279+
: `Up to ${
280+
selectedAssetId === IRON_ASSET_ID_HEX
281+
? "8"
282+
: (getAssetDecimals(assetMap.get(selectedAssetId)) ?? "0")
283+
} decimal places`)
284+
}
285+
keyboardType="decimal-pad"
204286
/>
205287

206288
<Input
@@ -244,17 +326,25 @@ export default function Send() {
244326
disabled={
245327
transactionState !== "idle" ||
246328
isValidPublicAddress.data !== true ||
247-
!isValidBigInt(amount) ||
329+
!amount ||
330+
!!amountError ||
248331
(selectedFee === "custom" && !isValidBigInt(customFee))
249332
}
250333
onPress={async () => {
251334
try {
252335
setTransactionState("sending");
253336

337+
const [amountInMinorUnits] =
338+
convertAmountToMinor(amount, selectedAssetId, assetMap) ?? [];
339+
340+
if (!amountInMinorUnits) {
341+
throw new Error("Invalid amount");
342+
}
343+
254344
const outputs = [
255345
{
256346
publicAddress: selectedRecipient,
257-
amount: amount,
347+
amount: amountInMinorUnits.toString(),
258348
memo: memo,
259349
assetId: selectedAssetId,
260350
},

0 commit comments

Comments
 (0)