Skip to content

Commit 31e04bb

Browse files
committed
refactor(ecash): improve send-transaction UI components
1 parent c85168c commit 31e04bb

3 files changed

Lines changed: 102 additions & 59 deletions

File tree

packages/extension/src/providers/ecash/ui/send-transaction/components/send-address-input.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const props = defineProps({
3535
},
3636
network: {
3737
type: Object as PropType<ECashNetwork>,
38-
default: () => ({}),
38+
required: true,
3939
},
4040
from: {
4141
type: Boolean,
@@ -60,7 +60,10 @@ const xecAddress = computed(() => {
6060
});
6161
6262
const isAddressValid = computed(() => {
63-
return isValidECashAddress(xecAddress.value);
63+
return isValidECashAddress(
64+
xecAddress.value,
65+
props.network.cashAddrPrefix ?? 'ecash',
66+
);
6467
});
6568
6669
const address = computed({

packages/extension/src/providers/ecash/ui/send-transaction/index.vue

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151

5252
<send-fee-select
5353
:in-swap="false"
54-
:selected-fee="selectedFee"
55-
:fee="gasCostValues[selectedFee]"
54+
:selected-fee="GasPriceTypes.REGULAR"
55+
:fee="gasCostValues[GasPriceTypes.REGULAR]"
5656
/>
5757

5858
<send-alert
@@ -111,7 +111,6 @@ import { isValidECashAddress } from '@/providers/ecash/libs/utils';
111111
import { VerifyTransactionParams } from '@/providers/bitcoin/ui/types';
112112
import { trackSendEvents } from '@/libs/metrics';
113113
import { SendEventType } from '@/libs/metrics/types';
114-
import RecentlySentAddressesState from '@/libs/recently-sent-addresses';
115114
import ChronikAPI from '@/providers/ecash/libs/api-chronik';
116115
import {
117116
calculateTransactionFee,
@@ -164,7 +163,6 @@ const amountInBase = computed(() =>
164163
);
165164
166165
const isMaxSelected = ref<boolean>(false);
167-
const selectedFee = ref<GasPriceTypes>(GasPriceTypes.REGULAR);
168166
const gasCostValues = ref<GasFeeType>(defaultGasCostVals);
169167
const addressFrom = ref<string>(
170168
props.accountInfo.selectedAccount?.address ?? '',
@@ -187,7 +185,9 @@ const belowDust = computed(() => {
187185
);
188186
});
189187
190-
const currentGasFee = computed(() => gasCostValues.value[selectedFee.value]);
188+
const currentGasFee = computed(
189+
() => gasCostValues.value[GasPriceTypes.REGULAR],
190+
);
191191
192192
const isBalanceZero = computed(() => {
193193
return UTXOBalance.value.isZero();
@@ -257,7 +257,13 @@ const sendButtonTitle = computed(() => {
257257
const isInputsValid = computed<boolean>(() => {
258258
if (isCalculatingMax.value) return false;
259259
260-
if (!isValidECashAddress(addressTo.value)) return false;
260+
if (
261+
!isValidECashAddress(
262+
addressTo.value,
263+
props.network.cashAddrPrefix ?? 'ecash',
264+
)
265+
)
266+
return false;
261267
if (!isValidDecimals(sendAmount.value, selectedAsset.value.decimals!))
262268
return false;
263269
@@ -375,14 +381,7 @@ const inputAmount = (inputAmount: string) => {
375381
amount.value = inputAmountBn.lt(0) ? '0' : inputAmount;
376382
};
377383
378-
const recentlySentAddresses = new RecentlySentAddressesState();
379-
380384
const sendAction = async () => {
381-
await recentlySentAddresses.addRecentlySentAddress(
382-
props.network,
383-
addressTo.value,
384-
);
385-
386385
const keyring = new PublicKeyRing();
387386
const fromAccountInfo = await keyring.getAccount(addressFrom.value);
388387
@@ -409,7 +408,7 @@ const sendAction = async () => {
409408
fromAddress: fromAccountInfo.address,
410409
fromAddressName: fromAccountInfo.name,
411410
gasFee: currentGasFee.value,
412-
gasPriceType: selectedFee.value,
411+
gasPriceType: GasPriceTypes.REGULAR,
413412
toAddress: addressTo.value,
414413
};
415414

packages/extension/src/providers/ecash/ui/send-transaction/verify-transaction/index.vue

Lines changed: 84 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
<template>
22
<div class="container" :class="{ popup: isPopup }">
3-
<div v-if="network" class="verify-transaction">
3+
<div v-if="initError" class="verify-transaction__loading">
4+
<p style="color: #c00; text-align: center; padding: 16px">
5+
{{ initError }}
6+
</p>
7+
<div style="display: flex; justify-content: center; margin-top: 16px">
8+
<base-button title="Go Back" :click="close" :gray="true" />
9+
</div>
10+
</div>
11+
12+
<div v-else-if="network && txData" class="verify-transaction">
413
<custom-scrollbar
514
ref="verifyScrollRef"
615
class="verify-transaction__scroll-area"
@@ -66,7 +75,7 @@
6675
</div>
6776

6877
<send-process
69-
v-if="isProcessing"
78+
v-if="isProcessing && txData && network"
7079
v-model="isProcessing"
7180
:is-nft="false"
7281
:to-address="txData.toAddress"
@@ -79,7 +88,7 @@
7988
</template>
8089

8190
<script setup lang="ts">
82-
import { onBeforeMount, ref, ComponentPublicInstance } from 'vue';
91+
import { onBeforeMount, ref, computed, ComponentPublicInstance } from 'vue';
8392
import { useRoute, useRouter } from 'vue-router';
8493
import CloseIcon from '@action/icons/common/close-icon.vue';
8594
import BaseButton from '@action/components/base-button/index.vue';
@@ -102,46 +111,82 @@ import { trackSendEvents } from '@/libs/metrics';
102111
import { SendEventType } from '@/libs/metrics/types';
103112
import sendUsingInternalMessengers from '@/libs/messenger/internal-messenger';
104113
import { InternalMethods } from '@/types/messenger';
114+
import RecentlySentAddressesState from '@/libs/recently-sent-addresses';
105115
106116
const POPUP_CLOSE_DELAY = 4500;
107117
const WINDOW_CLOSE_DELAY = 1500;
108118
109119
const KeyRing = new PublicKeyRing();
110120
const route = useRoute();
111121
const router = useRouter();
112-
const selectedNetwork: string = route.query.id as string;
113122
114-
const txData: VerifyTransactionParams = JSON.parse(
115-
Buffer.from(route.query.txData as string, 'base64').toString('utf8'),
116-
);
123+
const selectedNetwork = ref<string>('');
124+
const txData = ref<VerifyTransactionParams | null>(null);
117125
118126
const isProcessing = ref(false);
119-
const network = ref<ECashNetwork>();
127+
const network = ref<ECashNetwork | null>(null);
120128
const isSendDone = ref(false);
121-
const account = ref<EnkryptAccount>();
129+
const account = ref<EnkryptAccount | undefined>(undefined);
122130
const isPopup: boolean = getCurrentContext() === 'new-window';
123131
const verifyScrollRef = ref<ComponentPublicInstance<HTMLElement>>();
124132
const isWindowPopup = ref(false);
125133
const errorMsg = ref('');
134+
const initError = ref('');
126135
127136
defineExpose({ verifyScrollRef });
128137
129-
import { computed } from 'vue';
130-
131138
const displayFromAddress = computed(() => {
132-
if (!network.value) return '';
133-
return network.value.displayAddress(txData.fromAddress);
139+
if (!network.value || !txData.value) return '';
140+
return network.value.displayAddress(txData.value.fromAddress);
134141
});
135142
136143
const isInPopupContext = computed(() => getCurrentContext() === 'popup');
137144
138145
onBeforeMount(async () => {
139-
network.value = (await getNetworkByName(selectedNetwork)!) as ECashNetwork;
140-
if (network.value) {
146+
try {
147+
const rawId = route.query.id;
148+
const rawTxData = route.query.txData;
149+
150+
if (!rawId || typeof rawId !== 'string') {
151+
throw new Error('Missing or invalid network id in route.');
152+
}
153+
if (!rawTxData || typeof rawTxData !== 'string') {
154+
throw new Error('Missing or invalid transaction data in route.');
155+
}
156+
157+
selectedNetwork.value = rawId;
158+
txData.value = JSON.parse(
159+
Buffer.from(rawTxData, 'base64').toString('utf8'),
160+
) as VerifyTransactionParams;
161+
} catch (e: any) {
162+
initError.value = `Could not load transaction data: ${e.message}`;
163+
return;
164+
}
165+
166+
try {
167+
const resolvedNetwork = await getNetworkByName(selectedNetwork.value);
168+
if (!resolvedNetwork) {
169+
throw new Error(`Unknown network: "${selectedNetwork.value}"`);
170+
}
171+
network.value = resolvedNetwork as ECashNetwork;
141172
trackSendEvents(SendEventType.SendVerify, { network: network.value.name });
173+
} catch (e: any) {
174+
initError.value = `Could not load network: ${e.message}`;
175+
return;
176+
}
177+
178+
try {
179+
const resolvedAccount = await KeyRing.getAccount(txData.value!.fromAddress);
180+
if (!resolvedAccount) {
181+
throw new Error(
182+
`Account not found for address: ${txData.value!.fromAddress}`,
183+
);
184+
}
185+
account.value = resolvedAccount;
186+
isWindowPopup.value = resolvedAccount.isHardware;
187+
} catch (e: any) {
188+
initError.value = `Could not load account: ${e.message}`;
142189
}
143-
account.value = await KeyRing.getAccount(txData.fromAddress);
144-
isWindowPopup.value = account.value.isHardware;
145190
});
146191
147192
const close = () => {
@@ -155,7 +200,6 @@ const close = () => {
155200
const closeAfterSend = (delay: number) => {
156201
setTimeout(() => {
157202
isProcessing.value = false;
158-
159203
if (isInPopupContext.value) {
160204
router.go(-2);
161205
} else {
@@ -166,25 +210,25 @@ const closeAfterSend = (delay: number) => {
166210
167211
const createTxActivity = (): Activity => ({
168212
from: displayFromAddress.value,
169-
to: txData.toAddress,
170-
isIncoming: txData.fromAddress === txData.toAddress,
213+
to: txData.value!.toAddress,
214+
isIncoming: txData.value!.fromAddress === txData.value!.toAddress,
171215
network: network.value!.name,
172216
status: ActivityStatus.pending,
173217
timestamp: new Date().getTime(),
174218
token: {
175-
decimals: txData.toToken.decimals,
176-
icon: txData.toToken.icon,
177-
name: txData.toToken.name,
178-
symbol: txData.toToken.symbol,
179-
price: txData.toToken.price,
219+
decimals: txData.value!.toToken.decimals,
220+
icon: txData.value!.toToken.icon,
221+
name: txData.value!.toToken.name,
222+
symbol: txData.value!.toToken.symbol,
223+
price: txData.value!.toToken.price,
180224
},
181225
type: ActivityType.transaction,
182-
value: txData.toToken.amount,
226+
value: txData.value!.toToken.amount,
183227
transactionHash: '',
184228
});
185229
186230
const sendAction = async () => {
187-
if (!network.value || !account.value) return;
231+
if (!network.value || !account.value || !txData.value) return;
188232
189233
isProcessing.value = true;
190234
trackSendEvents(SendEventType.SendApprove, {
@@ -196,8 +240,8 @@ const sendAction = async () => {
196240
197241
try {
198242
const signParams: any = {
199-
toAddress: txData.toAddress,
200-
amount: txData.toToken.amount,
243+
toAddress: txData.value.toAddress,
244+
amount: txData.value.toToken.amount,
201245
account: account.value,
202246
networkName: network.value.name,
203247
};
@@ -213,25 +257,22 @@ const sendAction = async () => {
213257
214258
const { txid } = JSON.parse(result.result!);
215259
260+
const recentlySentAddresses = new RecentlySentAddressesState();
261+
await recentlySentAddresses.addRecentlySentAddress(
262+
network.value,
263+
txData.value.toAddress,
264+
);
265+
216266
trackSendEvents(SendEventType.SendComplete, {
217267
network: network.value.name,
218268
});
219269
220-
activityState.addActivities(
221-
[
222-
{
223-
...txActivity,
224-
transactionHash: txid,
225-
},
226-
],
227-
{
228-
address: displayFromAddress.value,
229-
network: network.value.name,
230-
},
231-
);
270+
activityState.addActivities([{ ...txActivity, transactionHash: txid }], {
271+
address: displayFromAddress.value,
272+
network: network.value.name,
273+
});
232274
233275
isSendDone.value = true;
234-
235276
const delay = isInPopupContext.value
236277
? POPUP_CLOSE_DELAY
237278
: WINDOW_CLOSE_DELAY;
@@ -244,7 +285,7 @@ const sendAction = async () => {
244285
245286
txActivity.status = ActivityStatus.failed;
246287
activityState.addActivities([txActivity], {
247-
address: txData.fromAddress,
288+
address: txData.value.fromAddress,
248289
network: network.value.name,
249290
});
250291

0 commit comments

Comments
 (0)