From 2d2f1b858e382d801712fb6f79c0371c07ce45d2 Mon Sep 17 00:00:00 2001 From: Vitalii Date: Fri, 14 Jul 2023 16:05:45 +0300 Subject: [PATCH] web/satellite: show pending transactions during token upgrade flow Made UI updates to reflect pending token payments during upgrade account flow. So pending transactions with confirmations count are displayed on Add STORJ Tokens step of upgrade flow. While this modal is open we make a request to storjscan once in 20 seconds to get recent confirmations count. When all transactions become confirmed we show success view where a sum of STORJ tokens received is displayed. Issue: https://github.com/storj/storj/issues/5978 Change-Id: Icfdc1e5080ed58cea1822cb7d85551ba8064c636 --- web/satellite/src/api/payments.ts | 34 +++++ .../upgradeAccountFlow/AddTokensStep.vue | 105 ++++++++++----- .../AddTokensStepBanner.vue | 124 ++++++++++++++++++ .../src/store/modules/billingStore.ts | 29 ++++ web/satellite/src/types/payments.ts | 29 ++++ .../images/modals/upgradeFlow/check.svg | 3 + .../images/modals/upgradeFlow/pending.svg | 3 + 7 files changed, 297 insertions(+), 30 deletions(-) create mode 100644 web/satellite/src/components/modals/upgradeAccountFlow/AddTokensStepBanner.vue create mode 100644 web/satellite/static/images/modals/upgradeFlow/check.svg create mode 100644 web/satellite/static/images/modals/upgradeFlow/pending.svg diff --git a/web/satellite/src/api/payments.ts b/web/satellite/src/api/payments.ts index cbaf9b09d..6d798e77b 100644 --- a/web/satellite/src/api/payments.ts +++ b/web/satellite/src/api/payments.ts @@ -15,6 +15,7 @@ import { TokenAmount, NativePaymentHistoryItem, Wallet, + PaymentWithConfirmations, } from '@/types/payments'; import { HttpClient } from '@/utils/httpClient'; import { Time } from '@/utils/time'; @@ -285,6 +286,39 @@ export class PaymentsHttpApi implements PaymentsApi { return []; } + /** + * Returns a list of STORJ token payments with confirmations. + * + * @returns list of native token payment items with confirmations + * @throws Error + */ + public async paymentsWithConfirmations(): Promise { + const path = `${this.ROOT_PATH}/wallet/payments-with-confirmations`; + const response = await this.client.get(path); + + if (!response.ok) { + throw new Error('Can not list token payment with confirmations'); + } + + const json = await response.json(); + if (json && json.length) { + return json.map(item => + new PaymentWithConfirmations( + item.to, + parseFloat(item.tokenValue), + parseFloat(item.usdValue), + item.transaction, + new Date(item.timestamp), + parseFloat(item.bonusTokens), + item.status, + item.confirmations, + ), + ); + } + + return []; + } + /** * applyCouponCode applies a coupon code. * diff --git a/web/satellite/src/components/modals/upgradeAccountFlow/AddTokensStep.vue b/web/satellite/src/components/modals/upgradeAccountFlow/AddTokensStep.vue index ef3775444..39e5caa9b 100644 --- a/web/satellite/src/components/modals/upgradeAccountFlow/AddTokensStep.vue +++ b/web/satellite/src/components/modals/upgradeAccountFlow/AddTokensStep.vue @@ -2,7 +2,7 @@ // See LICENSE for copying information. diff --git a/web/satellite/src/store/modules/billingStore.ts b/web/satellite/src/store/modules/billingStore.ts index 721b59214..7c529861a 100644 --- a/web/satellite/src/store/modules/billingStore.ts +++ b/web/satellite/src/store/modules/billingStore.ts @@ -14,6 +14,8 @@ import { PaymentsHistoryItem, PaymentsHistoryItemStatus, PaymentsHistoryItemType, + PaymentStatus, + PaymentWithConfirmations, ProjectCharges, ProjectUsagePriceModel, Wallet, @@ -24,6 +26,7 @@ export class PaymentsState { public balance: AccountBalance = new AccountBalance(); public creditCards: CreditCard[] = []; public paymentsHistory: PaymentsHistoryItem[] = []; + public pendingPaymentsWithConfirmations: PaymentWithConfirmations[] = []; public nativePaymentsHistory: NativePaymentHistoryItem[] = []; public projectCharges: ProjectCharges = new ProjectCharges(); public usagePriceModel: ProjectUsagePriceModel = new ProjectUsagePriceModel(); @@ -92,6 +95,10 @@ export const useBillingStore = defineStore('billing', () => { }); } + function clearPendingPayments(): void { + state.pendingPaymentsWithConfirmations = []; + } + async function makeCardDefault(id: string): Promise { await api.makeCreditCardDefault(id); @@ -122,6 +129,25 @@ export const useBillingStore = defineStore('billing', () => { state.nativePaymentsHistory = await api.nativePaymentsHistory(); } + async function getPaymentsWithConfirmations(): Promise { + const newPayments = await api.paymentsWithConfirmations(); + newPayments.forEach(newPayment => { + const oldPayment = state.pendingPaymentsWithConfirmations.find(old => old.transaction === newPayment.transaction); + + if (newPayment.status === PaymentStatus.Pending) { + if (oldPayment) { + oldPayment.confirmations = newPayment.confirmations; + return; + } + + state.pendingPaymentsWithConfirmations.push(newPayment); + return; + } + + if (oldPayment) oldPayment.status = PaymentStatus.Confirmed; + }); + } + async function getProjectUsageAndChargesCurrentRollup(): Promise { const now = new Date(); const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes())); @@ -169,6 +195,7 @@ export const useBillingStore = defineStore('billing', () => { state.nativePaymentsHistory = []; state.projectCharges = new ProjectCharges(); state.usagePriceModel = new ProjectUsagePriceModel(); + state.pendingPaymentsWithConfirmations = []; state.startDate = new Date(); state.endDate = new Date(); state.coupon = null; @@ -214,6 +241,8 @@ export const useBillingStore = defineStore('billing', () => { getNativePaymentsHistory, getProjectUsageAndChargesCurrentRollup, getProjectUsageAndChargesPreviousRollup, + getPaymentsWithConfirmations, + clearPendingPayments, getProjectUsagePriceModel, applyCouponCode, getCoupon, diff --git a/web/satellite/src/types/payments.ts b/web/satellite/src/types/payments.ts index 096e89fd4..e0009ba12 100644 --- a/web/satellite/src/types/payments.ts +++ b/web/satellite/src/types/payments.ts @@ -78,6 +78,14 @@ export interface PaymentsApi { */ nativePaymentsHistory(): Promise; + /** + * Returns a list of STORJ token payments with confirmations. + * + * @returns list of native token payment items with confirmations + * @throws Error + */ + paymentsWithConfirmations(): Promise; + /** * applyCouponCode applies a coupon code. * @@ -625,6 +633,27 @@ export class NativePaymentHistoryItem { } } +export enum PaymentStatus { + Pending = 'pending', + Confirmed = 'confirmed', +} + +/** + * PaymentWithConfirmation holds all information about token payment with confirmations count. + */ +export class PaymentWithConfirmations { + public constructor( + public readonly address: string = '', + public readonly tokenValue: number = 0, + public readonly usdValue: number = 0, + public readonly transaction: string = '', + public readonly timestamp: Date = new Date(), + public readonly bonusTokens: number = 0, + public status: PaymentStatus = PaymentStatus.Confirmed, + public confirmations: number = 0, + ) { } +} + export class TokenAmount { public constructor( private readonly _value: string = '0.0', diff --git a/web/satellite/static/images/modals/upgradeFlow/check.svg b/web/satellite/static/images/modals/upgradeFlow/check.svg new file mode 100644 index 000000000..38ca03bfd --- /dev/null +++ b/web/satellite/static/images/modals/upgradeFlow/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/satellite/static/images/modals/upgradeFlow/pending.svg b/web/satellite/static/images/modals/upgradeFlow/pending.svg new file mode 100644 index 000000000..09f9e2d18 --- /dev/null +++ b/web/satellite/static/images/modals/upgradeFlow/pending.svg @@ -0,0 +1,3 @@ + + +