web/satellite: see token payments history

This change lists token payment histories from storjscan/coinpayments on the "Payment Methods > Storj Tokens" page

see: https://github.com/storj/storj/issues/4941

Change-Id: I178ba7940c4cb132f05673607030725a4c4b3e1c
This commit is contained in:
Wilfred Asomani 2022-08-23 10:37:46 +00:00
parent fe3aedebe8
commit 05e57edb20
11 changed files with 607 additions and 414 deletions

View File

@ -11,7 +11,9 @@ import {
PaymentsApi, PaymentsApi,
PaymentsHistoryItem, PaymentsHistoryItem,
ProjectUsageAndCharges, ProjectUsageAndCharges,
TokenAmount,
TokenDeposit, TokenDeposit,
NativePaymentHistoryItem,
Wallet, Wallet,
} from '@/types/payments'; } from '@/types/payments';
import { HttpClient } from '@/utils/httpClient'; import { HttpClient } from '@/utils/httpClient';
@ -236,6 +238,43 @@ export class PaymentsHttpApi implements PaymentsApi {
return []; return [];
} }
/**
* Returns a list of native token payments.
*
* @returns list of native token payment history items
* @throws Error
*/
public async nativePaymentsHistory(): Promise<NativePaymentHistoryItem[]> {
const path = `${this.ROOT_PATH}/wallet/payments`;
const response = await this.client.get(path);
if (!response.ok) {
if (response.status === 401) {
throw new ErrorUnauthorized();
}
throw new Error('Can not list token payment history');
}
const json = await response.json();
if (!json) return [];
if (json.payments) {
return json.payments.map(item =>
new NativePaymentHistoryItem(
item.ID,
item.Wallet,
item.Type,
new TokenAmount(item.Amount.value, item.Amount.currency),
new TokenAmount(item.Received.value, item.Received.currency),
item.Status,
item.Link,
new Date(item.Timestamp),
),
);
}
return [];
}
/** /**
* makeTokenDeposit process coin payments. * makeTokenDeposit process coin payments.
* *

View File

@ -26,11 +26,16 @@
import { Component, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
import { PaymentsHistoryItem, PaymentsHistoryItemType } from '@/types/payments'; import { PaymentsHistoryItem, PaymentsHistoryItemType } from '@/types/payments';
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import BillingHistoryHeader from '@/components/account/billing/billingTabs/BillingHistoryHeader.vue'; import BillingHistoryHeader from '@/components/account/billing/billingTabs/BillingHistoryHeader.vue';
import BillingHistoryItem from '@/components/account/billing/billingTabs/BillingHistoryItem.vue'; import BillingHistoryItem from '@/components/account/billing/billingTabs/BillingHistoryItem.vue';
import VTable from '@/components/common/VTable.vue'; import VTable from '@/components/common/VTable.vue';
const {
GET_PAYMENTS_HISTORY,
} = PAYMENTS_ACTIONS;
// @vue/component // @vue/component
@Component({ @Component({
components: { components: {
@ -42,6 +47,18 @@ import VTable from '@/components/common/VTable.vue';
export default class BillingArea extends Vue { export default class BillingArea extends Vue {
mounted(): void {
this.fetchHistory();
}
public async fetchHistory(): Promise<void> {
try {
await this.$store.dispatch(GET_PAYMENTS_HISTORY);
} catch (error) {
await this.$notify.error(error.message);
}
}
public get historyItems(): PaymentsHistoryItem[] { public get historyItems(): PaymentsHistoryItem[] {
return this.$store.state.paymentsModule.paymentsHistory.filter((item: PaymentsHistoryItem) => { return this.$store.state.paymentsModule.paymentsHistory.filter((item: PaymentsHistoryItem) => {
return item.type === PaymentsHistoryItemType.Invoice || item.type === PaymentsHistoryItemType.Charge; return item.type === PaymentsHistoryItemType.Invoice || item.type === PaymentsHistoryItemType.Charge;

View File

@ -5,42 +5,21 @@
<div class="payments-area"> <div class="payments-area">
<div class="payments-area__top-container"> <div class="payments-area__top-container">
<h1 class="payments-area__title"> <h1 class="payments-area__title">
Payment Methods{{ showTransactions? ' > Storj Tokens':null }} <span class="payments-area__title__back" @click="hideTransactionsTable">Payment Methods</span>{{ showTransactions? ' > Storj Tokens':null }}
</h1> </h1>
<VButton
v-if="showTransactions"
label="Add Funds with CoinPayments"
font-size="13px"
height="40px"
width="220px"
:on-press="showAddFundsCard"
/>
</div> </div>
<div v-if="!showTransactions" class="payments-area__container"> <div v-if="!showTransactions" class="payments-area__container">
<add-token-card-native v-if="nativeTokenPaymentsEnabled" /> <v-loader
<template v-else> v-if="nativePayIsLoading"
<v-loader />
v-if="!tokensAreLoaded" <add-token-card-native
/> v-else-if="nativeTokenPaymentsEnabled && wallet.address"
<div v-else-if="!showAddFunds"> @showTransactions="showTransactionsTable"
<balance-token-card />
v-for="item in mostRecentTransaction" <add-token-card
:key="item.id" v-else
:v-if="tokensAreLoaded" :total-count="transactionCount"
:billing-item="item" />
:show-add-funds="showAddFunds"
@showTransactions="toggleTransactionsTable"
@toggleShowAddFunds="toggleShowAddFunds"
/>
</div>
<div v-else>
<add-token-card
:total-count="transactionCount"
@toggleShowAddFunds="toggleShowAddFunds"
@fetchHistory="addTokenHelper"
/>
</div>
</template>
<div v-for="card in creditCards" :key="card.id" class="payments-area__container__cards"> <div v-for="card in creditCards" :key="card.id" class="payments-area__container__cards">
<CreditCardContainer <CreditCardContainer
:credit-card="card" :credit-card="card"
@ -135,59 +114,80 @@
</div> </div>
</div> </div>
<div v-if="showTransactions"> <div v-if="showTransactions">
<div class="payments-area__container__transactions"> <div class="payments-area__address-card">
<SortingHeader2 <div class="payments-area__address-card__left">
@sortFunction="sortFunction" <canvas ref="canvas" class="payments-area__address-card__left__canvas" />
/> <div class="payments-area__address-card__left__balance">
<token-transaction-item <p class="payments-area__address-card__left__balance__label">
v-for="item in displayedHistory" Available Balance (USD)
:key="item.id" </p>
:billing-item="item" <p class="payments-area__address-card__left__balance__value">
/> {{ wallet.balance.value }}
<div class="divider" />
<div class="pagination">
<div class="pagination__total">
<p>
{{ transactionCount }} transactions found
</p> </p>
</div> </div>
<div class="pagination__right-container"> </div>
<div
v-if="transactionCount > 0" <div class="payments-area__address-card__right">
class="pagination__right-container__count" <div class="payments-area__address-card__right__address">
> <p class="payments-area__address-card__right__address__label">
<span v-if="transactionCount > 10 && paginationLocation.end !== transactionCount"> Deposit Address
{{ paginationLocation.start + 1 }} - {{ paginationLocation.end }} of {{ transactionCount }} </p>
</span> <p class="payments-area__address-card__right__address__value">
<span v-else> {{ wallet.address }}
{{ paginationLocation.start + 1 }} - {{ transactionCount }} of {{ transactionCount }} </p>
</span> </div>
</div> <div class="payments-area__address-card__right__copy">
<div <VButton
v-if="transactionCount > 10" class="modal__address__copy-button"
class="pagination__right-container__buttons" label="Copy Address"
> width="8.6rem"
<ArrowIcon height="2.5rem"
class="pagination__right-container__buttons__left" font-size="0.9rem"
@click="paginationController(-10)" icon="copy"
/> :on-press="onCopyAddressClick"
<ArrowIcon />
v-if="paginationLocation.end < transactionCount - 1"
class="pagination__right-container__buttons__right"
@click="paginationController(10)"
/>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="payments-area__transactions-area">
<h2 class="payments-area__transactions-area__title">Transactions</h2>
<v-table
class="payments-area__transactions-area__table"
items-label="transactions"
:items="displayedHistory"
:limit="pageSize"
:total-page-count="pageCount"
:total-items-count="transactionCount"
:on-page-click-callback="paginationController"
>
<template #head>
<SortingHeader2
@sortFunction="sortFunction"
/>
</template>
<template #body>
<token-transaction-item
v-for="item in displayedHistory"
:key="item.id"
:item="item"
/>
</template>
</v-table>
</div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
import QRCode from 'qrcode';
import { CreditCard, PaymentsHistoryItem, PaymentsHistoryItemType } from '@/types/payments'; import {
CreditCard,
Wallet,
NativePaymentHistoryItem,
} from '@/types/payments';
import { USER_ACTIONS } from '@/store/modules/users'; import { USER_ACTIONS } from '@/store/modules/users';
import { PAYMENTS_ACTIONS } from '@/store/modules/payments'; import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import { RouteConfig } from '@/router'; import { RouteConfig } from '@/router';
@ -200,12 +200,11 @@ import VLoader from '@/components/common/VLoader.vue';
import CreditCardContainer from '@/components/account/billing/billingTabs/CreditCardContainer.vue'; import CreditCardContainer from '@/components/account/billing/billingTabs/CreditCardContainer.vue';
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue'; import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
import SortingHeader2 from '@/components/account/billing/depositAndBillingHistory/SortingHeader2.vue'; import SortingHeader2 from '@/components/account/billing/depositAndBillingHistory/SortingHeader2.vue';
import BalanceTokenCard from '@/components/account/billing/paymentMethods/BalanceTokenCard.vue';
import AddTokenCard from '@/components/account/billing/paymentMethods/AddTokenCard.vue'; import AddTokenCard from '@/components/account/billing/paymentMethods/AddTokenCard.vue';
import AddTokenCardNative from '@/components/account/billing/paymentMethods/AddTokenCardNative.vue'; import AddTokenCardNative from '@/components/account/billing/paymentMethods/AddTokenCardNative.vue';
import TokenTransactionItem from '@/components/account/billing/paymentMethods/TokenTransactionItem.vue'; import TokenTransactionItem from '@/components/account/billing/paymentMethods/TokenTransactionItem.vue';
import VTable from '@/components/common/VTable.vue';
import ArrowIcon from '@/../static/images/common/arrowRight.svg';
import CloseCrossIcon from '@/../static/images/common/closeCross.svg'; import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
import AmericanExpressIcon from '@/../static/images/payments/cardIcons/smallamericanexpress.svg'; import AmericanExpressIcon from '@/../static/images/payments/cardIcons/smallamericanexpress.svg';
import DinersIcon from '@/../static/images/payments/cardIcons/smalldinersclub.svg'; import DinersIcon from '@/../static/images/payments/cardIcons/smalldinersclub.svg';
@ -229,15 +228,13 @@ const {
GET_CREDIT_CARDS, GET_CREDIT_CARDS,
REMOVE_CARD, REMOVE_CARD,
MAKE_CARD_DEFAULT, MAKE_CARD_DEFAULT,
GET_PAYMENTS_HISTORY, GET_NATIVE_PAYMENTS_HISTORY,
} = PAYMENTS_ACTIONS; } = PAYMENTS_ACTIONS;
const paginationStartNumber = 0;
const paginationEndNumber = 10;
// @vue/component // @vue/component
@Component({ @Component({
components: { components: {
VTable,
AmericanExpressIcon, AmericanExpressIcon,
DiscoverIcon, DiscoverIcon,
JCBIcon, JCBIcon,
@ -247,14 +244,12 @@ const paginationEndNumber = 10;
VButton, VButton,
TokenTransactionItem, TokenTransactionItem,
SortingHeader2, SortingHeader2,
ArrowIcon,
CloseCrossIcon, CloseCrossIcon,
CreditCardImage, CreditCardImage,
StripeCardInput, StripeCardInput,
DinersIcon, DinersIcon,
Trash, Trash,
CreditCardContainer, CreditCardContainer,
BalanceTokenCard,
AddTokenCard, AddTokenCard,
AddTokenCardNative, AddTokenCardNative,
VLoader, VLoader,
@ -267,14 +262,10 @@ export default class PaymentMethods extends Vue {
* controls token inputs and transaction table * controls token inputs and transaction table
*/ */
public showTransactions = false; public showTransactions = false;
public showAddFunds = false; public displayedHistory: NativePaymentHistoryItem[] = [];
public mostRecentTransaction: PaymentsHistoryItem[] = [];
public paginationLocation: {start: number, end: number} = { start: paginationStartNumber, end: paginationEndNumber };
public tokenHistory: {amount: number, start: Date, status: string,}[] = [];
public displayedHistory: Record<string, unknown>[] = [];
public transactionCount = 0; public transactionCount = 0;
public tokensAreLoaded = false; public nativePayIsLoading = true;
public reloadKey = 0; public pageSize = 10;
/** /**
* controls card inputs * controls card inputs
@ -286,61 +277,67 @@ export default class PaymentMethods extends Vue {
public isChangeDefaultPaymentModalOpen = false; public isChangeDefaultPaymentModalOpen = false;
public defaultCreditCardSelection = ''; public defaultCreditCardSelection = '';
public isRemovePaymentMethodsModalOpen = false; public isRemovePaymentMethodsModalOpen = false;
public isAddCardClicked = false;
public $refs!: { public $refs!: {
stripeCardInput: StripeCardInput & StripeForm; stripeCardInput: StripeCardInput & StripeForm;
canvas: HTMLCanvasElement;
}; };
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi(); private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public beforeMount() { public mounted(): void {
this.fetchHistory(); this.claimWallet();
} }
public addTokenHelper(): void { private get wallet(): Wallet {
this.fetchHistory(); return this.$store.state.paymentsModule.wallet;
this.toggleShowAddFunds();
} }
public async fetchHistory(): Promise<void> { public onCopyAddressClick(): void {
this.tokensAreLoaded = false; this.$copyText(this.wallet.address);
this.$notify.success('Address copied to your clipboard');
}
public async claimWallet(): Promise<void> {
try { try {
await this.$store.dispatch(GET_PAYMENTS_HISTORY); if (this.nativeTokenPaymentsEnabled && !this.wallet.address)
this.fetchHelper(this.depositHistoryItems); await this.$store.dispatch(PAYMENTS_ACTIONS.CLAIM_WALLET);
this.reloadKey = this.reloadKey + 1;
} catch (error) { } catch (error) {
await this.$notify.error(error.message); await this.$notify.error(error.message);
} finally {
this.nativePayIsLoading = false;
} }
} }
public fetchHelper(tokenArray): void { public async fetchHistory(): Promise<void> {
this.mostRecentTransaction = [tokenArray[0]]; this.nativePayIsLoading = true;
this.tokenHistory = tokenArray; try {
this.transactionCount = tokenArray.length; await this.$store.dispatch(GET_NATIVE_PAYMENTS_HISTORY);
this.displayedHistory = tokenArray.slice(0,10); this.transactionCount = this.nativePaymentHistoryItems.length;
this.tokensAreLoaded = true; this.displayedHistory = this.nativePaymentHistoryItems.slice(0,this.pageSize);
this.showAddFunds = this.transactionCount <= 0; } catch (error) {
await this.$notify.error(error.message);
} finally {
this.nativePayIsLoading = false;
}
} }
public toggleShowAddFunds(): void { public async hideTransactionsTable(): Promise<void> {
this.showAddFunds = !this.showAddFunds;
}
public showAddFundsCard(): void {
this.showTransactions = false; this.showTransactions = false;
this.showAddFunds = true;
} }
public toggleTransactionsTable(): void { public async showTransactionsTable(): Promise<void> {
this.showAddFunds = true; await this.fetchHistory();
this.showTransactions = !this.showTransactions; this.showTransactions = true;
await Vue.nextTick();
await this.prepQRCode();
} }
/** public async prepQRCode() {
* Returns TokenTransactionItem item component. try {
*/ await QRCode.toCanvas(this.$refs.canvas, this.wallet.address);
public get itemComponent(): typeof TokenTransactionItem { } catch (error) {
return TokenTransactionItem; await this.$notify.error(error.message);
}
} }
public async updatePaymentMethod(): Promise<void> { public async updatePaymentMethod(): Promise<void> {
@ -459,73 +456,51 @@ export default class PaymentMethods extends Vue {
* controls sorting the transaction table * controls sorting the transaction table
*/ */
public sortFunction(key) { public sortFunction(key) {
this.paginationLocation = { start: 0, end: 10 };
this.displayedHistory = this.tokenHistory.slice(0,10);
switch (key) { switch (key) {
case 'date-ascending': case 'date-ascending':
this.tokenHistory.sort((a,b) => {return a.start.getTime() - b.start.getTime();}); this.nativePaymentHistoryItems.sort((a,b) => {return a.timestamp.getTime() - b.timestamp.getTime();});
break; break;
case 'date-descending': case 'date-descending':
this.tokenHistory.sort((a,b) => {return b.start.getTime() - a.start.getTime();}); this.nativePaymentHistoryItems.sort((a,b) => {return b.timestamp.getTime() - a.timestamp.getTime();});
break; break;
case 'amount-ascending': case 'amount-ascending':
this.tokenHistory.sort((a,b) => {return a.amount - b.amount;}); this.nativePaymentHistoryItems.sort((a,b) => {return a.amount.value - b.amount.value;});
break; break;
case 'amount-descending': case 'amount-descending':
this.tokenHistory.sort((a,b) => {return b.amount - a.amount;}); this.nativePaymentHistoryItems.sort((a,b) => {return b.amount.value - a.amount.value;});
break; break;
case 'status-ascending': case 'status-ascending':
this.tokenHistory.sort((a, b) => { this.nativePaymentHistoryItems.sort((a, b) => {
if (a.status < b.status) {return -1;} if (a.status < b.status) {return -1;}
if (a.status > b.status) {return 1;} if (a.status > b.status) {return 1;}
return 0;}); return 0;});
break; break;
case 'status-descending': case 'status-descending':
this.tokenHistory.sort((a, b) => { this.nativePaymentHistoryItems.sort((a, b) => {
if (b.status < a.status) {return -1;} if (b.status < a.status) {return -1;}
if (b.status > a.status) {return 1;} if (b.status > a.status) {return 1;}
return 0;}); return 0;});
break; break;
} }
this.displayedHistory = this.nativePaymentHistoryItems.slice(0,10);
} }
/** /**
* controls transaction table pagination * controls transaction table pagination
*/ */
public paginationController(i): void { public paginationController(i): void {
let diff = this.transactionCount - this.paginationLocation.start; this.displayedHistory = this.nativePaymentHistoryItems.slice((i - 1) * this.pageSize,((i - 1) * this.pageSize) + this.pageSize);
if (this.paginationLocation.start + i >= 0 && this.paginationLocation.end + i <= this.transactionCount && this.paginationLocation.end !== this.transactionCount){ }
this.paginationLocation = {
start: this.paginationLocation.start + i,
end: this.paginationLocation.end + i,
};
} else if (this.paginationLocation.start + i < 0 ) {
this.paginationLocation = {
start: 0,
end: 10,
};
} else if (this.paginationLocation.end + i > this.transactionCount) {
this.paginationLocation = {
start: this.paginationLocation.start + i,
end: this.transactionCount,
};
} else if (this.paginationLocation.end === this.transactionCount) {
this.paginationLocation = {
start: this.paginationLocation.start + i,
end: this.transactionCount - (diff),
};
}
this.displayedHistory = this.tokenHistory.slice(this.paginationLocation.start, this.paginationLocation.end); public get pageCount(): number {
return Math.ceil(this.transactionCount / this.pageSize);
} }
/** /**
* Returns deposit history items. * Returns deposit history items.
*/ */
public get depositHistoryItems(): PaymentsHistoryItem[] { public get nativePaymentHistoryItems(): NativePaymentHistoryItem[] {
return this.$store.state.paymentsModule.paymentsHistory.filter((item: PaymentsHistoryItem) => { return this.$store.state.paymentsModule.nativePaymentsHistory;
return item.type === PaymentsHistoryItemType.Transaction || item.type === PaymentsHistoryItemType.DepositBonus;
});
} }
} }
</script> </script>
@ -841,6 +816,14 @@ $align: center;
font-family: sans-serif; font-family: sans-serif;
font-size: 24px; font-size: 24px;
margin: 20px 0; margin: 20px 0;
&__back {
cursor: pointer;
&:hover {
color: #000000bd;
}
}
} }
&__container { &__container {
@ -934,6 +917,94 @@ $align: center;
} }
} }
} }
&__address-card {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
background: #fff;
box-shadow: 0 0 20px rgb(0 0 0 / 4%);
border-radius: 0.6rem;
padding: 1rem 1.5rem;
font-family: 'font_regular', sans-serif;
&__left {
display: flex;
align-items: center;
gap: 1.5rem;
&__canvas {
height: 4rem !important;
width: 4rem !important;
}
&__balance {
display: flex;
flex-direction: column;
justify-content: center;
gap: 0.3rem;
&__label {
font-size: 0.9rem;
color: rgb(0 0 0 / 75%);
}
&__value {
font-family: 'font_bold', sans-serif;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
@media screen and (max-width: 375px) {
width: 16rem;
}
}
}
}
&__right {
width: 60%;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 0.3rem;
&__address {
display: flex;
flex-direction: column;
justify-content: center;
gap: 0.3rem;
&__label {
font-size: 0.9rem;
color: rgb(0 0 0 / 75%);
}
&__value {
font-family: 'font_bold', sans-serif;
}
}
}
}
&__transactions-area {
margin-top: 1.5rem;
display: flex;
flex-direction: column;
align-items: start;
gap: 1.5rem;
&__title {
font-family: 'font_regular', sans-serif;
font-size: 1.5rem;
line-height: 1.8rem;
}
&__table {
width: 100%;
}
}
} }
@mixin reset-list { @mixin reset-list {

View File

@ -2,48 +2,50 @@
// See LICENSE for copying information. // See LICENSE for copying information.
<template> <template>
<div class="sort-header-container"> <fragment>
<div <th @click="sortFunction('date')">
class="sort-header-container__item date" <div class="th-content">
@click="sortFunction('date')" <span>DATE</span>
> <VerticalArrows
<p class="sort-header-container__item__name">DATE</p> :is-active="arrowController.date"
<VerticalArrows :direction="dateSortDirection"
:is-active="arrowController.date" />
:direction="dateSortDirection" </div>
/> </th>
</div> <th>
<div class="sort-header-container__item transaction"> <div class="th-content">
<p class="sort-header-container__item__name">TRANSACTION</p> <span>TRANSACTION</span>
</div> </div>
<div </th>
class="sort-header-container__item amount" <th @click="sortFunction('amount')">
@click="sortFunction('amount')" <div class="th-content">
> <span>AMOUNT(USD)</span>
<p class="sort-header-container__item__name">AMOUNT(USD)</p> <VerticalArrows
<VerticalArrows :is-active="arrowController.amount"
:is-active="arrowController.amount" :direction="amountSortDirection"
:direction="amountSortDirection" />
/> </div>
</div> </th>
<div <th @click="sortFunction('status')">
class="sort-header-container__item status" <div class="th-content">
@click="sortFunction('status')" <span>STATUS</span>
> <VerticalArrows
<p class="sort-header-container__item__name">STATUS</p> :is-active="arrowController.status"
<VerticalArrows :direction="statusSortDirection"
:is-active="arrowController.status" />
:direction="statusSortDirection" </div>
/> </th>
</div> <th class="laptop">
<div class="sort-header-container__item details"> <div class="th-content">
<p class="sort-header-container__item__name">DETAILS</p> <span>DETAILS</span>
</div> </div>
</div> </th>
</fragment>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
import { Fragment } from 'vue-fragment';
import { SortDirection } from '@/types/common'; import { SortDirection } from '@/types/common';
@ -53,6 +55,7 @@ import VerticalArrows from '@/components/common/VerticalArrows.vue';
@Component({ @Component({
components: { components: {
VerticalArrows, VerticalArrows,
Fragment,
}, },
}) })
export default class SortingHeader2 extends Vue { export default class SortingHeader2 extends Vue {
@ -69,7 +72,7 @@ export default class SortingHeader2 extends Vue {
/** /**
* sorts table by date * sorts table by date
*/ */
public sortFunction(key): void { public sortFunction(key): void {
switch (key) { switch (key) {
case 'date': case 'date':
@ -98,51 +101,15 @@ export default class SortingHeader2 extends Vue {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.sort-header-container { .th-content {
display: flex; display: flex;
width: 100%; text-align: left;
padding: 16px 0; }
&__item { @media screen and (max-width: 1024px) and (min-width: 426px) {
text-align: left;
&__name { .laptop {
font-family: 'font_medium', sans-serif; display: none;
font-size: 14px;
line-height: 19px;
color: #adadad;
margin: 0;
}
}
}
.date,
.amount,
.status {
display: flex;
cursor: pointer;
}
.date {
width: 15%;
}
.transaction {
width: 35%;
}
.status {
width: 15%;
}
.amount {
width: 15%;
margin: 0;
}
.details {
text-align: left;
margin: 0;
width: 20%;
} }
}
</style> </style>

View File

@ -18,7 +18,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
import StorjLarge from '@/../static/images/billing/storj-icon-large.svg'; import StorjLarge from '@/../static/images/billing/storj-icon-large.svg';
@ -29,8 +29,6 @@ import StorjLarge from '@/../static/images/billing/storj-icon-large.svg';
}, },
}) })
export default class AddTokenCard extends Vue { export default class AddTokenCard extends Vue {
@Prop({ default: 0 })
private readonly totalCount: number;
} }
</script> </script>
@ -72,6 +70,8 @@ export default class AddTokenCard extends Vue {
&__add-funds { &__add-funds {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center;
gap: 1rem;
height: 100%; height: 100%;
width: 100%; width: 100%;

View File

@ -2,64 +2,59 @@
// See LICENSE for copying information. // See LICENSE for copying information.
<template> <template>
<div class="token"> <div v-if="wallet.address" class="token">
<div class="token__icon"> <div class="token__icon">
<div class="token__icon__wrapper"> <div class="token__icon__wrapper">
<StorjLarge /> <StorjLarge />
</div> </div>
</div> </div>
<v-loader v-if="isLoading" /> <div class="token__title-area">
<template v-if="!isLoading && !wallet.address"> <div class="token__title-area__small-icon">
<h1 class="token__title">STORJ Token</h1> <StorjSmall />
<p class="token__info"> </div>
Deposit STORJ Token to your account and receive a 10% bonus, or $10 for every $100. <div class="token__title-area__default-wrapper">
</p> <p class="token__title-area__default-wrapper__label">Default</p>
<v-button <VInfo>
label="Add STORJ Tokens" <template #icon>
width="150px" <InfoIcon />
height="40px" </template>
<template #message>
<p class="token__title-area__default-wrapper__message">
If the STORJ token balance runs out, the default credit card will be charged.
<a
class="token__title-area__default-wrapper__message__link"
href=""
target="_blank"
rel="noopener noreferrer"
>
Learn More
</a>
</p>
</template>
</VInfo>
</div>
</div>
<div class="token__info-area">
<div class="token__info-area__option">
<h2 class="token__info-area__option__title">STORJ Token Deposit Address</h2>
<p class="token__info-area__option__value">{{ wallet.address }}</p>
</div>
<div class="token__info-area__option">
<h2 class="token__info-area__option__title">Total Balance</h2>
<p class="token__info-area__option__value">{{ wallet.balance.value }}</p>
</div>
</div>
<div class="token__action-area">
<VButton
class="token__action-area__history-btn"
label="See transactions"
is-transparent="true"
height="32px"
font-size="13px" font-size="13px"
border-radius="8px" border-radius="6px"
:on-press="onAddTokensClick" :on-press="() => $emit('showTransactions')"
/> />
</template>
<template v-if="!isLoading && wallet.address">
<div class="token__title-area">
<div class="token__title-area__small-icon">
<StorjSmall />
</div>
<div class="token__title-area__default-wrapper">
<p class="token__title-area__default-wrapper__label">Default</p>
<VInfo>
<template #icon>
<InfoIcon />
</template>
<template #message>
<p class="token__title-area__default-wrapper__message">
If the STORJ token balance runs out, the default credit card will be charged.
<a
class="token__title-area__default-wrapper__message__link"
href=""
target="_blank"
rel="noopener noreferrer"
>
Learn More
</a>
</p>
</template>
</VInfo>
</div>
</div>
<div class="token__info-area">
<div class="token__info-area__option">
<h2 class="token__info-area__option__title">STORJ Token Deposit Address</h2>
<p class="token__info-area__option__value">{{ wallet.address }}</p>
</div>
<div class="token__info-area__option">
<h2 class="token__info-area__option__title">Total Balance</h2>
<p class="token__info-area__option__value">{{ wallet.balance | centsToDollars }}</p>
</div>
</div>
<v-button <v-button
label="Add funds" label="Add funds"
width="96px" width="96px"
@ -68,14 +63,13 @@
border-radius="6px" border-radius="6px"
:on-press="onAddTokensClick" :on-press="onAddTokensClick"
/> />
</template> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator'; import { Component, Vue } from 'vue-property-decorator';
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants'; import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
import { Wallet } from '@/types/payments'; import { Wallet } from '@/types/payments';
import { AnalyticsHttpApi } from '@/api/analytics'; import { AnalyticsHttpApi } from '@/api/analytics';
@ -83,7 +77,6 @@ import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import VButton from '@/components/common/VButton.vue'; import VButton from '@/components/common/VButton.vue';
import VInfo from '@/components/common/VInfo.vue'; import VInfo from '@/components/common/VInfo.vue';
import VLoader from '@/components/common/VLoader.vue';
import InfoIcon from '@/../static/images/billing/blueInfoIcon.svg'; import InfoIcon from '@/../static/images/billing/blueInfoIcon.svg';
import StorjSmall from '@/../static/images/billing/storj-icon-small.svg'; import StorjSmall from '@/../static/images/billing/storj-icon-small.svg';
@ -96,29 +89,12 @@ import StorjLarge from '@/../static/images/billing/storj-icon-large.svg';
StorjSmall, StorjSmall,
StorjLarge, StorjLarge,
VButton, VButton,
VLoader,
VInfo, VInfo,
}, },
}) })
export default class AddTokenCardNative extends Vue { export default class AddTokenCardNative extends Vue {
public isLoading = true;
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi(); private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Mounted hook after initial render.
* Fetches wallet from backend.
*/
public async mounted(): Promise<void> {
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_WALLET);
} catch (error) {
await this.$notify.error(error.message);
} finally {
this.isLoading = false;
}
}
/** /**
* Holds on add tokens button click logic. * Holds on add tokens button click logic.
* Triggers Add funds popup. * Triggers Add funds popup.
@ -132,9 +108,7 @@ export default class AddTokenCardNative extends Vue {
* Returns wallet from store. * Returns wallet from store.
*/ */
private get wallet(): Wallet { private get wallet(): Wallet {
// TODO: remove this when backend is ready. return this.$store.state.paymentsModule.wallet;
return { address: 'ijefiw54et945t89459ty8e98c4jyc8489yec985yce8i59y8c598yc56', balance: 234234 };
// return this.$store.state.paymentsModule.wallet;
} }
} }
</script> </script>
@ -270,6 +244,27 @@ export default class AddTokenCardNative extends Vue {
} }
} }
} }
&__action-area {
display: flex;
justify-content: start;
align-items: center;
gap: 10px;
&__history-btn {
cursor: pointer;
padding: 0 10px;
span {
font-size: 13px;
color: #56606d;
font-family: 'font_medium', sans-serif;
line-height: 23px;
margin: 0;
white-space: nowrap;
}
}
}
} }
:deep(.info__box) { :deep(.info__box) {

View File

@ -2,76 +2,130 @@
// See LICENSE for copying information. // See LICENSE for copying information.
<template> <template>
<div class="container"> <tr @click="goToTxn">
<div class="divider" /> <th class="align-left data mobile">
<div class="container__row"> <div class="few-items">
<div class="container__row__item__date-container"> <p class="array-val">
<p class="container__row__item date">{{ billingItem.start.toLocaleDateString() }}</p> Deposit on {{ item.formattedType }}
<p class="container__row__item time">{{ billingItem.start.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'}) }}</p> </p>
<p class="array-val">
<span v-if="item.type === 'storjscan'">{{ item.amount.value }}</span>
<span v-else>{{ item.received.value }}</span>
</p>
<p
class="array-val" :class="{
pending_txt: item.status === 'pending',
confirmed_txt: item.status === 'confirmed',
rejected_txt: item.status === 'rejected',
}"
>
{{ item.formattedStatus }}
</p>
<p class="array-val">
{{ item.timestamp.toLocaleDateString() }}
</p>
</div> </div>
<div class="container__row__item__description"> </th>
<p class="container__row__item__description__text">CoinPayments {{ billingItem.description.includes("Deposit")? "Deposit": "Withdrawal" }}</p>
<p class="container__row__item__description__id">{{ billingItem.id }}</p> <fragment>
</div> <th class="align-left data tablet-laptop">
<p class="container__row__item amount"> <p>{{ item.timestamp.toLocaleDateString() }}</p>
<b> </th>
<span v-if="billingItem.type === 1"> <th class="align-left data tablet-laptop">
${{ billingItem.quantity.received.toFixed(2) }} <p>Deposit on {{ item.formattedType }}</p>
</span> <p class="laptop">{{ item.wallet }}</p>
<span v-else> </th>
${{ billingItem.quantity.total.toFixed(2) }}
</span> <th class="align-right data tablet-laptop">
</b> <p v-if="item.type === 'storjscan'">{{ item.amount.value }}</p>
</p> <p v-else>{{ item.received.value }}</p>
<p class="container__row__item status"> </th>
<span :class="`container__row__item__circle-icon ${billingItem.status}`">
&#9679; <th class="align-left data tablet-laptop">
</span> <div class="status">
{{ billingItem.formattedStatus }} <span
</p> class="status__dot" :class="{
<p class="container__row__item download"> pending: item.status === 'pending',
<a v-if="billingItem.link" class="download-link" target="_blank" :href="billingItem.link">View On CoinPayments</a> confirmed: item.status === 'confirmed',
</p> rejected: item.status === 'rejected'
</div> }"
</div> />
<span class="status__text">{{ item.formattedStatus }}</span>
</div>
</th>
<th class="align-left data laptop">
<a
v-if="item.link" class="download-link" target="_blank"
rel="noopener noreferrer" :href="item.link"
>View on {{ item.formattedType }}</a>
</th>
</fragment>
</tr>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Prop, Vue, Component } from 'vue-property-decorator'; import { Prop, Component } from 'vue-property-decorator';
import { Fragment } from 'vue-fragment';
import { PaymentsHistoryItem } from '@/types/payments'; import { NativePaymentHistoryItem } from '@/types/payments';
import Resizable from '@/components/common/Resizable.vue';
// @vue/component // @vue/component
@Component @Component({
export default class TokenTransactionItem extends Vue { components: { Fragment },
@Prop({ default: () => new PaymentsHistoryItem() }) })
private readonly billingItem: PaymentsHistoryItem; export default class TokenTransactionItem extends Resizable {
@Prop({ default: () => new NativePaymentHistoryItem() })
private readonly item: NativePaymentHistoryItem;
public goToTxn() {
if (this.isMobile || this.isTablet)
window.open(this.item.link, '_blank', 'noreferrer');
}
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.pending { .pending {
background: #ffa800;
}
.pending_txt {
color: #ffa800; color: #ffa800;
} }
.confirmed { .confirmed {
background: #00ac26;
}
.confirmed_txt {
color: #00ac26; color: #00ac26;
} }
.rejected { .rejected {
background: #ac1a00;
}
.rejected_txt {
color: #ac1a00; color: #ac1a00;
} }
.divider { .status {
height: 1px; display: flex;
width: calc(100% + 30px); align-items: center;
background-color: #e5e7eb; gap: 0.5rem;
align-self: center;
&__dot {
height: 0.8rem;
width: 0.8rem;
border-radius: 100%;
}
} }
.download-link { .download-link {
color: #2683ff; color: #2683ff;
font-family: 'font_bold', sans-serif;
text-decoration: underline !important; text-decoration: underline !important;
&:hover { &:hover {
@ -79,69 +133,58 @@ export default class TokenTransactionItem extends Vue {
} }
} }
.container { .few-items {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between;
}
&__row { .array-val {
display: flex; font-family: 'font_regular', sans-serif;
align-items: center; font-size: 0.75rem;
width: 100%; line-height: 1.25rem;
&__item { &:first-of-type {
font-family: sans-serif; font-family: 'font_bold', sans-serif;
font-weight: 300; font-size: 0.875rem;
font-size: 16px; margin-bottom: 3px;
text-align: left;
margin: 30px 0;
&__description {
width: 35%;
display: flex;
flex-direction: column;
text-align: left;
&__text,
&__id {
font-family: 'font_medium', sans-serif;
}
}
&__date-container {
width: 15%;
display: flex;
flex-direction: column;
}
}
} }
} }
.date { @media only screen and (max-width: 425px) {
font-family: 'font_bold', sans-serif;
margin: 0; .mobile {
display: table-cell;
}
.laptop,
.tablet-laptop {
display: none;
}
} }
.time { @media only screen and (min-width: 426px) {
color: #6b7280;
margin: 0; .tablet-laptop {
font-size: 14px; display: table-cell;
}
.mobile {
display: none;
}
} }
.description { @media only screen and (max-width: 1024px) and (min-width: 426px) {
font-family: 'font_medium', sans-serif;
overflow: ellipse; .laptop {
display: none;
}
} }
.status { @media only screen and (min-width: 1024px) {
width: 15%;
}
.amount { .laptop {
width: 15%; display: table-cell;
} }
.download {
text-align: left;
width: 20%;
} }
</style> </style>

View File

@ -137,9 +137,7 @@ export default class AddTokenFundsModal extends Vue {
* Returns wallet from store. * Returns wallet from store.
*/ */
private get wallet(): Wallet { private get wallet(): Wallet {
// TODO: remove this when backend is ready. return this.$store.state.paymentsModule.wallet;
return { address: 'ijefiw54et945t89459ty8e98c4jyc8489yec985yce8i59y8c598yc56', balance: 234234 };
// return this.$store.state.paymentsModule.wallet;
} }
} }
</script> </script>

View File

@ -12,6 +12,7 @@ import {
PaymentsHistoryItemType, PaymentsHistoryItemType,
ProjectUsageAndCharges, ProjectUsageAndCharges,
TokenDeposit, TokenDeposit,
NativePaymentHistoryItem,
Wallet, Wallet,
} from '@/types/payments'; } from '@/types/payments';
import { StoreModule } from '@/types/store'; import { StoreModule } from '@/types/store';
@ -25,6 +26,7 @@ export const PAYMENTS_MUTATIONS = {
UPDATE_CARDS_SELECTION: 'UPDATE_CARDS_SELECTION', UPDATE_CARDS_SELECTION: 'UPDATE_CARDS_SELECTION',
UPDATE_CARDS_DEFAULT: 'UPDATE_CARDS_DEFAULT', UPDATE_CARDS_DEFAULT: 'UPDATE_CARDS_DEFAULT',
SET_PAYMENTS_HISTORY: 'SET_PAYMENTS_HISTORY', SET_PAYMENTS_HISTORY: 'SET_PAYMENTS_HISTORY',
SET_NATIVE_PAYMENTS_HISTORY: 'SET_NATIVE_PAYMENTS_HISTORY',
SET_PROJECT_USAGE_AND_CHARGES: 'SET_PROJECT_USAGE_AND_CHARGES', SET_PROJECT_USAGE_AND_CHARGES: 'SET_PROJECT_USAGE_AND_CHARGES',
SET_CURRENT_ROLLUP_PRICE: 'SET_CURRENT_ROLLUP_PRICE', SET_CURRENT_ROLLUP_PRICE: 'SET_CURRENT_ROLLUP_PRICE',
SET_PREVIOUS_ROLLUP_PRICE: 'SET_PREVIOUS_ROLLUP_PRICE', SET_PREVIOUS_ROLLUP_PRICE: 'SET_PREVIOUS_ROLLUP_PRICE',
@ -46,6 +48,7 @@ export const PAYMENTS_ACTIONS = {
MAKE_CARD_DEFAULT: 'makeCardDefault', MAKE_CARD_DEFAULT: 'makeCardDefault',
REMOVE_CARD: 'removeCard', REMOVE_CARD: 'removeCard',
GET_PAYMENTS_HISTORY: 'getPaymentsHistory', GET_PAYMENTS_HISTORY: 'getPaymentsHistory',
GET_NATIVE_PAYMENTS_HISTORY: 'getNativePaymentsHistory',
MAKE_TOKEN_DEPOSIT: 'makeTokenDeposit', MAKE_TOKEN_DEPOSIT: 'makeTokenDeposit',
GET_PROJECT_USAGE_AND_CHARGES: 'getProjectUsageAndCharges', GET_PROJECT_USAGE_AND_CHARGES: 'getProjectUsageAndCharges',
GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP: 'getProjectUsageAndChargesCurrentRollup', GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP: 'getProjectUsageAndChargesCurrentRollup',
@ -63,6 +66,7 @@ const {
UPDATE_CARDS_SELECTION, UPDATE_CARDS_SELECTION,
UPDATE_CARDS_DEFAULT, UPDATE_CARDS_DEFAULT,
SET_PAYMENTS_HISTORY, SET_PAYMENTS_HISTORY,
SET_NATIVE_PAYMENTS_HISTORY,
SET_PROJECT_USAGE_AND_CHARGES, SET_PROJECT_USAGE_AND_CHARGES,
SET_PRICE_SUMMARY, SET_PRICE_SUMMARY,
SET_PRICE_SUMMARY_FOR_SELECTED_PROJECT, SET_PRICE_SUMMARY_FOR_SELECTED_PROJECT,
@ -82,6 +86,7 @@ const {
MAKE_CARD_DEFAULT, MAKE_CARD_DEFAULT,
REMOVE_CARD, REMOVE_CARD,
GET_PAYMENTS_HISTORY, GET_PAYMENTS_HISTORY,
GET_NATIVE_PAYMENTS_HISTORY,
MAKE_TOKEN_DEPOSIT, MAKE_TOKEN_DEPOSIT,
GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP, GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP,
GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP, GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP,
@ -96,6 +101,7 @@ export class PaymentsState {
public balance: AccountBalance = new AccountBalance(); public balance: AccountBalance = new AccountBalance();
public creditCards: CreditCard[] = []; public creditCards: CreditCard[] = [];
public paymentsHistory: PaymentsHistoryItem[] = []; public paymentsHistory: PaymentsHistoryItem[] = [];
public nativePaymentsHistory: NativePaymentHistoryItem[] = [];
public usageAndCharges: ProjectUsageAndCharges[] = []; public usageAndCharges: ProjectUsageAndCharges[] = [];
public priceSummary = 0; public priceSummary = 0;
public priceSummaryForSelectedProject = 0; public priceSummaryForSelectedProject = 0;
@ -166,6 +172,9 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState,
[SET_PAYMENTS_HISTORY](state: PaymentsState, paymentsHistory: PaymentsHistoryItem[]): void { [SET_PAYMENTS_HISTORY](state: PaymentsState, paymentsHistory: PaymentsHistoryItem[]): void {
state.paymentsHistory = paymentsHistory; state.paymentsHistory = paymentsHistory;
}, },
[SET_NATIVE_PAYMENTS_HISTORY](state: PaymentsState, paymentsHistory: NativePaymentHistoryItem[]): void {
state.nativePaymentsHistory = paymentsHistory;
},
[SET_PROJECT_USAGE_AND_CHARGES](state: PaymentsState, usageAndCharges: ProjectUsageAndCharges[]): void { [SET_PROJECT_USAGE_AND_CHARGES](state: PaymentsState, usageAndCharges: ProjectUsageAndCharges[]): void {
state.usageAndCharges = usageAndCharges; state.usageAndCharges = usageAndCharges;
}, },
@ -200,6 +209,7 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState,
[CLEAR](state: PaymentsState) { [CLEAR](state: PaymentsState) {
state.balance = new AccountBalance(); state.balance = new AccountBalance();
state.paymentsHistory = []; state.paymentsHistory = [];
state.nativePaymentsHistory = [];
state.usageAndCharges = []; state.usageAndCharges = [];
state.priceSummary = 0; state.priceSummary = 0;
state.creditCards = []; state.creditCards = [];
@ -260,10 +270,15 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState,
commit(CLEAR); commit(CLEAR);
}, },
[GET_PAYMENTS_HISTORY]: async function({ commit }: PaymentsContext): Promise<void> { [GET_PAYMENTS_HISTORY]: async function({ commit }: PaymentsContext): Promise<void> {
const paymentsHistory: PaymentsHistoryItem[] = await api.paymentsHistory(); const paymentsHistory = await api.paymentsHistory();
commit(SET_PAYMENTS_HISTORY, paymentsHistory); commit(SET_PAYMENTS_HISTORY, paymentsHistory);
}, },
[GET_NATIVE_PAYMENTS_HISTORY]: async function({ commit }: PaymentsContext): Promise<void> {
const paymentsHistory = await api.nativePaymentsHistory();
commit(SET_NATIVE_PAYMENTS_HISTORY, paymentsHistory);
},
[MAKE_TOKEN_DEPOSIT]: async function(_context: PaymentsContext, amount: number): Promise<TokenDeposit> { [MAKE_TOKEN_DEPOSIT]: async function(_context: PaymentsContext, amount: number): Promise<TokenDeposit> {
return await api.makeTokenDeposit(amount); return await api.makeTokenDeposit(amount);
}, },

View File

@ -62,6 +62,14 @@ export interface PaymentsApi {
*/ */
paymentsHistory(): Promise<PaymentsHistoryItem[]>; paymentsHistory(): Promise<PaymentsHistoryItem[]>;
/**
* Returns a list of invoices, transactions and all others payments history items for payment account.
*
* @returns list of payments history items
* @throws Error
*/
nativePaymentsHistory(): Promise<NativePaymentHistoryItem[]>;
/** /**
* Creates token transaction in CoinPayments * Creates token transaction in CoinPayments
* *
@ -361,6 +369,41 @@ export enum CouponDuration {
export class Wallet { export class Wallet {
public constructor( public constructor(
public address: string = '', public address: string = '',
public balance: number = 0, public balance: TokenAmount = new TokenAmount(),
) { } ) { }
} }
/**
* TokenPaymentHistoryItem holds all public information about token payments history line.
*/
export class NativePaymentHistoryItem {
public constructor(
public readonly id: string = '',
public readonly wallet: string = '',
public readonly type: string = '',
public readonly amount: TokenAmount = new TokenAmount(),
public readonly received: TokenAmount = new TokenAmount(),
public readonly status: string = '',
public readonly link: string = '',
public readonly timestamp: Date = new Date(),
) { }
public get formattedStatus(): string {
return this.status.charAt(0).toUpperCase() + this.status.substring(1);
}
public get formattedType(): string {
return this.type.charAt(0).toUpperCase() + this.type.substring(1);
}
}
export class TokenAmount {
public constructor(
private readonly _value: string = '0.0',
public readonly currency: string = '',
) { }
public get value(): number {
return Number.parseFloat(this._value);
}
}

View File

@ -9,6 +9,7 @@ import {
PaymentsHistoryItem, PaymentsHistoryItem,
ProjectUsageAndCharges, ProjectUsageAndCharges,
TokenDeposit, TokenDeposit,
NativePaymentHistoryItem,
Wallet, Wallet,
} from '@/types/payments'; } from '@/types/payments';
@ -54,6 +55,10 @@ export class PaymentsMock implements PaymentsApi {
return Promise.resolve([]); return Promise.resolve([]);
} }
nativePaymentsHistory(): Promise<NativePaymentHistoryItem[]> {
return Promise.resolve([]);
}
makeTokenDeposit(amount: number): Promise<TokenDeposit> { makeTokenDeposit(amount: number): Promise<TokenDeposit> {
return Promise.resolve(new TokenDeposit(amount, 'testAddress', 'testLink')); return Promise.resolve(new TokenDeposit(amount, 'testAddress', 'testLink'));
} }