/
AssetAmountInput.svelte
129 lines (121 loc) · 4.86 KB
/
AssetAmountInput.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<script lang="typescript">
import Big from 'big.js'
import { Text, AssetDropdown, InputContainer, AmountInput, TooltipIcon } from 'shared/components'
import UnitInput from './UnitInput.svelte'
import { localize, parseCurrency } from '@core/i18n'
import {
formatTokenAmountBestMatch,
convertToRawAmount,
IAsset,
formatTokenAmountDefault,
visibleSelectedAccountAssets,
} from '@core/wallet'
import { IOTA_UNIT_MAP } from '@core/utils'
export let inputElement: HTMLInputElement = undefined
export let disabled = false
export let isFocused = false
export let asset: IAsset = $visibleSelectedAccountAssets?.baseCoin
export let rawAmount: string = undefined
export let unit: string = undefined
let amount: string = rawAmount ? formatTokenAmountDefault(Number(rawAmount), asset?.metadata, unit) : undefined
let amountInputElement: HTMLInputElement
let error: string
$: isFocused && (error = '')
let allowedDecimals = 0
$: if (!asset?.metadata?.useMetricPrefix) {
if (unit === asset?.metadata.unit) {
allowedDecimals = Math.min(asset?.metadata.decimals, 18)
} else if (unit === asset?.metadata?.subunit) {
allowedDecimals = 0
}
} else if (asset?.metadata?.useMetricPrefix) {
allowedDecimals = IOTA_UNIT_MAP?.[unit?.substring(0, 1)] ?? 0
}
function onClickAvailableBalance(): void {
const isRawAmount = asset?.metadata?.decimals && asset?.metadata?.unit
if (isRawAmount) {
const parsedAmount = formatTokenAmountDefault(asset?.balance?.available, asset?.metadata, unit)
amount = parsedAmount
unit = asset?.metadata?.unit
return
}
amount = asset?.balance.available.toString() ?? '0'
unit = undefined
}
export function validate(allowZeroOrNull = false): Promise<void> {
const amountAsFloat = parseCurrency(amount)
const isAmountZeroOrNull = !Number(amountAsFloat)
const bigAmount = convertToRawAmount(amount, unit, asset?.metadata)
// Zero value transactions can still contain metadata/tags
if (allowZeroOrNull && isAmountZeroOrNull) {
return
} else if (isAmountZeroOrNull) {
error = localize('error.send.amountInvalidFormat')
} else if (
(unit === asset?.metadata?.subunit ||
(unit === asset?.metadata?.unit && asset?.metadata?.decimals === 0)) &&
Number.parseInt(amount, 10).toString() !== amount
) {
error = localize('error.send.amountNoFloat')
} else if (bigAmount.gt(Big(asset?.balance?.available))) {
error = localize('error.send.amountTooHigh')
} else if (bigAmount.lte(Big(0))) {
error = localize('error.send.amountZero')
} else if (!bigAmount.mod(1).eq(Big(0))) {
error = localize('error.send.amountSmallerThanSubunit')
}
if (error) {
return Promise.reject(error)
}
rawAmount = bigAmount.toString()
}
</script>
<InputContainer
bind:this={inputElement}
bind:inputElement={amountInputElement}
col
{isFocused}
{error}
classes="space-y-2"
on:clickOutside={() => (isFocused = false)}
>
<div class="flex flex-row w-full items-center space-x-0.5 relative">
<AssetDropdown bind:asset />
<AmountInput
bind:inputElement={amountInputElement}
bind:amount
bind:hasFocus={isFocused}
maxDecimals={allowedDecimals}
isInteger={allowedDecimals === 0}
clearBackground
clearPadding
clearBorder
{disabled}
/>
{#if asset?.metadata?.unit}
<UnitInput bind:unit bind:isFocused tokenMetadata={asset?.metadata} />
{/if}
</div>
<div class="flex flex-row w-full items-end justify-between">
{#if asset}
<div class="flex flex-row items-center">
<button on:click={onClickAvailableBalance}>
<Text color="gray-600" darkColor="gray-500" fontSize="xs" classes="cursor-pointer">
{localize('general.availableBalanceWithValue', {
values: { balance: formatTokenAmountBestMatch(asset?.balance?.available, asset?.metadata) },
})}
</Text>
</button>
<TooltipIcon
title={localize('general.availableBalance')}
text={localize('general.availableBalanceTooltip')}
width={15}
height={15}
classes="ml-1"
/>
</div>
{/if}
<!-- Placeholder for asset USD value -->
<Text color="gray-600" darkColor="gray-500" fontSize="xs">-</Text>
</div>
</InputContainer>