web/satellite: available credits amount added on billing page

Change-Id: I9d9c18ad08cf150ceba078356e39132a602558d4
This commit is contained in:
VitaliiShpital 2020-03-26 15:34:16 +02:00 committed by Vitalii Shpital
parent 2d1a6968b0
commit 61b6ff5186
19 changed files with 405 additions and 180 deletions

View File

@ -84,7 +84,12 @@ export class AuthHttpApi {
*/
public async forgotPassword(email: string): Promise<void> {
const path = `${this.ROOT_PATH}/forgot-password/${email}`;
await this.http.post(path, email);
const response = await this.http.post(path, email);
if (response.ok) {
return;
}
throw new Error('There is no such email');
}
/**

View File

@ -2,7 +2,7 @@
// See LICENSE for copying information.
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectCharge, TokenDeposit } from '@/types/payments';
import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectUsageAndCharges, TokenDeposit } from '@/types/payments';
import { HttpClient } from '@/utils/httpClient';
import { toUnixTimestamp } from '@/utils/time';
@ -56,9 +56,9 @@ export class PaymentsHttpApi implements PaymentsApi {
}
/**
* projectsCharges returns how much money current user will be charged for each project which he owns.
* projectsUsageAndCharges returns usage and how much money current user will be charged for each project which he owns.
*/
public async projectsCharges(start: Date, end: Date): Promise<ProjectCharge[]> {
public async projectsUsageAndCharges(start: Date, end: Date): Promise<ProjectUsageAndCharges[]> {
const since = toUnixTimestamp(start).toString();
const before = toUnixTimestamp(end).toString();
const path = `${this.ROOT_PATH}/account/charges?from=${since}&to=${before}`;
@ -75,7 +75,7 @@ export class PaymentsHttpApi implements PaymentsApi {
const charges = await response.json();
if (charges) {
return charges.map(charge =>
new ProjectCharge(
new ProjectUsageAndCharges(
new Date(charge.since),
new Date(charge.before),
charge.egress,
@ -84,7 +84,8 @@ export class PaymentsHttpApi implements PaymentsApi {
charge.projectId,
charge.storagePrice,
charge.egressPrice,
charge.objectPrice),
charge.objectPrice,
),
);
}

View File

@ -152,7 +152,7 @@ export default class BillingArea extends Vue {
*/
public async beforeRouteLeave(to, from, next): Promise<void> {
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
} catch (error) {
await this.$notify.error(error.message);
}
@ -220,7 +220,7 @@ export default class BillingArea extends Vue {
start_date: this.dateRange.startDate,
end_date: this.dateRange.endDate,
});
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
} catch (error) {
await this.$notify.error(`Unable to fetch project charges. ${error.message}`);
}
@ -239,7 +239,7 @@ export default class BillingArea extends Vue {
start_date: this.dateRange.startDate,
end_date: this.dateRange.endDate,
});
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_PREVIOUS_ROLLUP);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP);
} catch (error) {
await this.$notify.error(`Unable to fetch project charges. ${error.message}`);
}
@ -274,7 +274,7 @@ export default class BillingArea extends Vue {
const dateRange: DateRange = new DateRange(startDate, endDate);
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES, dateRange);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES, dateRange);
} catch (error) {
await this.$notify.error(`Unable to fetch project charges. ${error.message}`);
}

View File

@ -5,26 +5,26 @@
<div class="current-month-area">
<div class="current-month-area__title-area">
<h1 class="current-month-area__title-area__title">Estimated Costs for This Billing Period</h1>
<span class="current-month-area__title-area__costs">{{ chargesSummary | centsToDollars }}</span>
<span class="current-month-area__title-area__costs">{{ priceSummary | centsToDollars }}</span>
</div>
<div class="current-month-area__content">
<h2 class="current-month-area__content__title">DETAILS</h2>
<div class="current-month-area__content__usage-charges" @click="toggleUsageChargesPopup">
<div class="current-month-area__content__usage-charges__head">
<div class="current-month-area__content__usage-charges__head__name-area">
<div class="current-month-area__content__usage-charges__head__name-area__image-container" v-if="usageCharges.length > 0">
<ArrowRightIcon v-if="!areUsageChargesShown"/>
<ArrowDownIcon v-if="areUsageChargesShown"/>
<div class="current-month-area__content__usage-charges__head__name-area__image-container" v-if="projectUsageAndCharges.length > 0">
<ArrowRightIcon v-if="!areProjectUsageAndChargesShown"/>
<ArrowDownIcon v-else/>
</div>
<span class="current-month-area__content__usage-charges__head__name-area__title">Usage Charges</span>
</div>
<span>Estimated total <span class="summary">{{ chargesSummary | centsToDollars }}</span></span>
<span>Estimated total <span class="summary">{{ priceSummary | centsToDollars }}</span></span>
</div>
<div class="current-month-area__content__usage-charges__content" v-if="areUsageChargesShown" @click.stop>
<UsageChargeItem
v-for="usageCharge in usageCharges"
:item="usageCharge"
:key="usageCharge.projectId"
<div class="current-month-area__content__usage-charges__content" v-if="areProjectUsageAndChargesShown" @click.stop>
<UsageAndChargesItem
v-for="usageAndCharges in projectUsageAndCharges"
:item="usageAndCharges"
:key="usageAndCharges.projectId"
class="item"
/>
</div>
@ -40,6 +40,14 @@
{{ balance | centsToDollars }}
</span>
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area">
<span class="current-month-area__content__credits-area__title-area__title">Available Credits</span>
</div>
<span class="current-month-area__content__credits-area__balance">
{{ availableBalance | centsToDollars }}
</span>
</div>
</div>
</div>
</template>
@ -47,19 +55,19 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import UsageChargeItem from '@/components/account/billing/estimatedCostsAndCredits/UsageChargeItem.vue';
import UsageAndChargesItem from '@/components/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.vue';
import VButton from '@/components/common/VButton.vue';
import ArrowRightIcon from '@/../static/images/common/BlueArrowRight.svg';
import ArrowDownIcon from '@/../static/images/common/BlueExpand.svg';
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
import { ProjectCharge } from '@/types/payments';
import { ProjectUsageAndCharges } from '@/types/payments';
@Component({
components: {
VButton,
UsageChargeItem,
UsageAndChargesItem,
ArrowRightIcon,
ArrowDownIcon,
},
@ -72,35 +80,29 @@ export default class EstimatedCostsAndCredits extends Vue {
public async mounted(): Promise<void> {
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
} catch (error) {
await this.$notify.error(error.message);
}
}
/**
* areUsageChargesShown indicates if area with all projects is expanded.
* areProjectUsageAndChargesShown indicates if area with all projects is expanded.
*/
private areUsageChargesShown: boolean = false;
public areProjectUsageAndChargesShown: boolean = false;
/**
* usageCharges is an array of all stored ProjectCharges.
* projectUsageAndCharges is an array of all stored ProjectUsageAndCharges.
*/
public get usageCharges(): ProjectCharge[] {
return this.$store.state.paymentsModule.charges;
public get projectUsageAndCharges(): ProjectUsageAndCharges[] {
return this.$store.state.paymentsModule.usageAndCharges;
}
/**
* chargesSummary returns summary of all projects.
* priceSummary returns price summary of usages for all the projects.
*/
public get chargesSummary(): number {
if (!this.usageCharges.length) {
return 0;
}
const usageItemSummaries = this.usageCharges.map(item => item.summary());
return usageItemSummaries.reduce((accumulator, current) => accumulator + current);
public get priceSummary(): number {
return this.$store.state.paymentsModule.priceSummary;
}
/**
@ -110,6 +112,22 @@ export default class EstimatedCostsAndCredits extends Vue {
return this.$store.state.paymentsModule.balance;
}
/**
* Returns available balance in cents.
*/
public get availableBalance(): number {
const total = this.previousRollupPrice + this.currentRollupPrice;
switch (true) {
case this.balance <= total:
return 0;
case this.$store.getters.isInvoiceForPreviousRollup:
return this.balance - this.currentRollupPrice;
default:
return this.balance - total;
}
}
/**
* Returns balance color red if balance below zero and clack if not.
*/
@ -121,11 +139,25 @@ export default class EstimatedCostsAndCredits extends Vue {
* toggleUsageChargesPopup is used to open/close area with list of project charges.
*/
public toggleUsageChargesPopup(): void {
if (this.usageCharges.length === 0) {
if (this.projectUsageAndCharges.length === 0) {
return;
}
this.areUsageChargesShown = !this.areUsageChargesShown;
this.areProjectUsageAndChargesShown = !this.areProjectUsageAndChargesShown;
}
/**
* previousRollupPrice is a price of previous rollup.
*/
private get previousRollupPrice(): number {
return this.$store.state.paymentsModule.previousRollupPrice;
}
/**
* currentRollupPrice is a price of current rollup.
*/
private get currentRollupPrice(): number {
return this.$store.state.paymentsModule.currentRollupPrice;
}
}
</script>

View File

@ -2,49 +2,49 @@
// See LICENSE for copying information.
<template>
<div class="usage-charge-item-container">
<div class="usage-charge-item-container__summary" @click.self="toggleDetailedInfo">
<div class="usage-charge-item-container__summary__name-container" @click="toggleDetailedInfo">
<svg class="usage-charge-item-container__summary__name-container__expand-image" v-if="!isDetailedInfoShown" width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<div class="usage-charges-item-container">
<div class="usage-charges-item-container__summary" @click.self="toggleDetailedInfo">
<div class="usage-charges-item-container__summary__name-container" @click="toggleDetailedInfo">
<svg class="usage-charges-item-container__summary__name-container__expand-image" v-if="!isDetailedInfoShown" width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.328889 13.6272C-0.10963 13.1302 -0.10963 12.3243 0.328889 11.8273L4.58792 7L0.328889 2.17268C-0.10963 1.67565 -0.10963 0.869804 0.328889 0.372774C0.767408 -0.124258 1.47839 -0.124258 1.91691 0.372774L7.76396 7L1.91691 13.6272C1.47839 14.1243 0.767409 14.1243 0.328889 13.6272Z" fill="#2683FF"/>
</svg>
<svg class="usage-charge-item-container__summary__name-container__expand-image" v-if="isDetailedInfoShown" width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg class="usage-charges-item-container__summary__name-container__expand-image" v-if="isDetailedInfoShown" width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.372773 0.338888C0.869804 -0.112963 1.67565 -0.112963 2.17268 0.338888L7 4.72741L11.8273 0.338888C12.3243 -0.112963 13.1302 -0.112963 13.6272 0.338888C14.1243 0.790739 14.1243 1.52333 13.6272 1.97519L7 8L0.372773 1.97519C-0.124258 1.52333 -0.124258 0.790739 0.372773 0.338888Z" fill="#2683FF"/>
</svg>
<span>{{ projectName }}</span>
</div>
<div class="usage-charge-item-container__summary__report-link" @click="onReportClick">Advanced Report -></div>
<div class="usage-charges-item-container__summary__report-link" @click="onReportClick">Advanced Report -></div>
</div>
<div class="usage-charge-item-container__detailed-info-container" v-if="isDetailedInfoShown">
<div class="usage-charge-item-container__detailed-info-container__info-header">
<div class="usage-charges-item-container__detailed-info-container" v-if="isDetailedInfoShown">
<div class="usage-charges-item-container__detailed-info-container__info-header">
<span class="resource-header">RESOURCE</span>
<span class="period-header">PERIOD</span>
<span class="usage-header">USAGE</span>
<span class="cost-header">COST</span>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area">
<div class="usage-charge-item-container__detailed-info-container__content-area__resource-container">
<div class="usage-charges-item-container__detailed-info-container__content-area">
<div class="usage-charges-item-container__detailed-info-container__content-area__resource-container">
<p>Storage ($0.010 per Gigabyte-Month)</p>
<p>Egress ($0.045 per GB)</p>
<p>Objects ($0.0000022 per Object-Month)</p>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area__period-container">
<div class="usage-charges-item-container__detailed-info-container__content-area__period-container">
<p>{{ period }}</p>
<p>{{ period }}</p>
<p>{{ period }}</p>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area__usage-container">
<div class="usage-charges-item-container__detailed-info-container__content-area__usage-container">
<p>{{ storageFormatted }} Gigabyte-month</p>
<p>{{ egressAmountAndDimension }}</p>
<p>{{ objectCountFormatted }} Object-month</p>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area__cost-container">
<div class="usage-charges-item-container__detailed-info-container__content-area__cost-container">
<p class="price">{{ item.storagePrice | centsToDollars }}</p>
<p class="price">{{ item.egressPrice | centsToDollars }}</p>
<p class="price">{{ item.objectPrice | centsToDollars }}</p>
</div>
</div>
<span class="usage-charge-item-container__detailed-info-container__summary">{{ item.summary() | centsToDollars }}</span>
<span class="usage-charges-item-container__detailed-info-container__summary">{{ item.summary() | centsToDollars }}</span>
</div>
</div>
</template>
@ -52,19 +52,19 @@
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { ProjectCharge } from '@/types/payments';
import { ProjectUsageAndCharges } from '@/types/payments';
import { Project } from '@/types/projects';
import { Size } from '@/utils/bytesSize';
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
import { toUnixTimestamp } from '@/utils/time';
@Component
export default class UsageChargeItem extends Vue {
export default class UsageAndChargesItem extends Vue {
/**
* item is an instance of ProjectCharge.
* item represents usage and charges of current project by period.
*/
@Prop({default: () => new ProjectCharge()})
private readonly item: ProjectCharge;
@Prop({default: () => new ProjectUsageAndCharges()})
private readonly item: ProjectUsageAndCharges;
/**
* HOURS_IN_MONTH constant shows amount of hours in 30-day month.
@ -165,7 +165,7 @@ export default class UsageChargeItem extends Vue {
margin: 0;
}
.usage-charge-item-container {
.usage-charges-item-container {
font-size: 16px;
line-height: 21px;
padding: 20px 0;

View File

@ -294,7 +294,7 @@ export default class PaymentMethods extends Vue {
this.isLoading = true;
if ((this.tokenDepositValue < 50 || this.tokenDepositValue >= this.MAX_TOKEN_AMOUNT) && !this.userHasOwnProject) {
if ((this.tokenDepositValue < 50 || this.tokenDepositValue >= this.MAX_TOKEN_AMOUNT) && !this.userHasOwnProject && this.noCreditCards) {
await this.$notify.error('First deposit amount must be more than 50 and less than 1000000');
this.tokenDepositValue = this.DEFAULT_TOKEN_DEPOSIT_VALUE;
this.areaState = PaymentMethodsBlockState.DEFAULT;

View File

@ -122,7 +122,7 @@ export default class TokenDepositSelection extends Vue {
* Returns payment options depending on user having his own project.
*/
public get options(): PaymentAmountOption[] {
if (!new ProjectOwning(this.$store).userHasOwnProject()) {
if (!new ProjectOwning(this.$store).userHasOwnProject() && this.noCreditCards) {
return this.initialPaymentOptions;
}
@ -175,7 +175,7 @@ export default class TokenDepositSelection extends Vue {
}
/**
* select standard value from list and emits it value to parent component
* select standard value from list and emits it value to parent component.
*/
public select(option: PaymentAmountOption): void {
this.isCustomAmount = false;
@ -183,6 +183,13 @@ export default class TokenDepositSelection extends Vue {
this.$emit('onChangeTokenValue', option.value);
this.close();
}
/**
* Indicates if user has no credit cards.
*/
private get noCreditCards(): boolean {
return this.$store.state.paymentsModule.creditCards.length === 0;
}
}
</script>

View File

@ -50,7 +50,7 @@ export default class ProjectSelectionDropdown extends Vue {
await this.$store.dispatch(PM_ACTIONS.SET_SEARCH_QUERY, '');
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
} catch (error) {
await this.$notify.error(`Unable to fetch project usage. ${error.message}`);
}

View File

@ -159,7 +159,7 @@ export default class NewProjectPopup extends Vue {
try {
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BILLING_HISTORY);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.createdProjectId);
} catch (error) {
await this.$notify.error(error.message);

View File

@ -9,7 +9,7 @@ import {
CreditCard,
DateRange,
PaymentsApi,
ProjectCharge,
ProjectUsageAndCharges,
TokenDeposit,
} from '@/types/payments';
@ -21,7 +21,10 @@ export const PAYMENTS_MUTATIONS = {
UPDATE_CARDS_SELECTION: 'UPDATE_CARDS_SELECTION',
UPDATE_CARDS_DEFAULT: 'UPDATE_CARDS_DEFAULT',
SET_BILLING_HISTORY: 'SET_BILLING_HISTORY',
SET_PROJECT_CHARGES: 'SET_PROJECT_CHARGES',
SET_PROJECT_USAGE_AND_CHARGES: 'SET_PROJECT_USAGE_AND_CHARGES',
SET_CURRENT_ROLLUP_PRICE: 'SET_CURRENT_ROLLUP_PRICE',
SET_PREVIOUS_ROLLUP_PRICE: 'SET_PREVIOUS_ROLLUP_PRICE',
SET_PRICE_SUMMARY: 'SET_PRICE_SUMMARY',
};
export const PAYMENTS_ACTIONS = {
@ -36,9 +39,9 @@ export const PAYMENTS_ACTIONS = {
REMOVE_CARD: 'removeCard',
GET_BILLING_HISTORY: 'getBillingHistory',
MAKE_TOKEN_DEPOSIT: 'makeTokenDeposit',
GET_PROJECT_CHARGES: 'getProjectCharges',
GET_PROJECT_CHARGES_CURRENT_ROLLUP: 'getProjectChargesCurrentRollup',
GET_PROJECT_CHARGES_PREVIOUS_ROLLUP: 'getProjectChargesPreviousRollup',
GET_PROJECT_USAGE_AND_CHARGES: 'getProjectUsageAndCharges',
GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP: 'getProjectUsageAndChargesCurrentRollup',
GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP: 'getProjectUsageAndChargesPreviousRollup',
};
const {
@ -49,7 +52,10 @@ const {
UPDATE_CARDS_SELECTION,
UPDATE_CARDS_DEFAULT,
SET_BILLING_HISTORY,
SET_PROJECT_CHARGES,
SET_PROJECT_USAGE_AND_CHARGES,
SET_CURRENT_ROLLUP_PRICE,
SET_PREVIOUS_ROLLUP_PRICE,
SET_PRICE_SUMMARY,
} = PAYMENTS_MUTATIONS;
const {
@ -64,9 +70,9 @@ const {
REMOVE_CARD,
GET_BILLING_HISTORY,
MAKE_TOKEN_DEPOSIT,
GET_PROJECT_CHARGES,
GET_PROJECT_CHARGES_CURRENT_ROLLUP,
GET_PROJECT_CHARGES_PREVIOUS_ROLLUP,
GET_PROJECT_USAGE_AND_CHARGES,
GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP,
GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP,
} = PAYMENTS_ACTIONS;
export class PaymentsState {
@ -76,7 +82,10 @@ export class PaymentsState {
public balance: number = 0;
public creditCards: CreditCard[] = [];
public billingHistory: BillingHistoryItem[] = [];
public charges: ProjectCharge[] = [];
public usageAndCharges: ProjectUsageAndCharges[] = [];
public priceSummary: number = 0;
public currentRollupPrice: number = 0;
public previousRollupPrice: number = 0;
public startDate: Date = new Date();
public endDate: Date = new Date();
}
@ -129,12 +138,36 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
[SET_BILLING_HISTORY](state: PaymentsState, billingHistory: BillingHistoryItem[]): void {
state.billingHistory = billingHistory;
},
[SET_PROJECT_CHARGES](state: PaymentsState, charges: ProjectCharge[]): void {
state.charges = charges;
[SET_PROJECT_USAGE_AND_CHARGES](state: PaymentsState, usageAndCharges: ProjectUsageAndCharges[]): void {
state.usageAndCharges = usageAndCharges;
},
[SET_CURRENT_ROLLUP_PRICE](state: PaymentsState): void {
state.currentRollupPrice = state.priceSummary;
},
[SET_PREVIOUS_ROLLUP_PRICE](state: PaymentsState): void {
state.previousRollupPrice = state.priceSummary;
},
[SET_PRICE_SUMMARY](state: PaymentsState, charges: ProjectUsageAndCharges[]): void {
if (charges.length === 0) {
state.priceSummary = 0;
return;
}
const usageItemSummaries = charges.map(item => item.summary());
state.priceSummary = usageItemSummaries.reduce((accumulator, current) => accumulator + current);
},
[CLEAR](state: PaymentsState) {
state.balance = 0;
state.billingHistory = [];
state.usageAndCharges = [];
state.priceSummary = 0;
state.previousRollupPrice = 0;
state.currentRollupPrice = 0;
state.creditCards = [];
state.startDate = new Date();
state.endDate = new Date();
},
},
actions: {
@ -185,7 +218,7 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
[MAKE_TOKEN_DEPOSIT]: async function({commit}: any, amount: number): Promise<TokenDeposit> {
return await api.makeTokenDeposit(amount);
},
[GET_PROJECT_CHARGES]: async function({commit}: any, dateRange: DateRange): Promise<void> {
[GET_PROJECT_USAGE_AND_CHARGES]: async function({commit}: any, dateRange: DateRange): Promise<void> {
const now = new Date();
let beforeUTC = new Date(Date.UTC(dateRange.endDate.getUTCFullYear(), dateRange.endDate.getUTCMonth(), dateRange.endDate.getUTCDate(), 23, 59));
@ -196,30 +229,35 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
}
const sinceUTC = new Date(Date.UTC(dateRange.startDate.getUTCFullYear(), dateRange.startDate.getUTCMonth(), dateRange.startDate.getUTCDate(), 0, 0));
const charges: ProjectCharge[] = await api.projectsCharges(sinceUTC, beforeUTC);
const usageAndCharges: ProjectUsageAndCharges[] = await api.projectsUsageAndCharges(sinceUTC, beforeUTC);
commit(SET_DATE, dateRange);
commit(SET_PROJECT_CHARGES, charges);
commit(SET_PROJECT_USAGE_AND_CHARGES, usageAndCharges);
commit(SET_PRICE_SUMMARY, usageAndCharges);
},
[GET_PROJECT_CHARGES_CURRENT_ROLLUP]: async function({commit}: any): Promise<void> {
[GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP]: async function({commit}: any): Promise<void> {
const now = new Date();
const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes()));
const startUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0));
const charges: ProjectCharge[] = await api.projectsCharges(startUTC, endUTC);
const usageAndCharges: ProjectUsageAndCharges[] = await api.projectsUsageAndCharges(startUTC, endUTC);
commit(SET_DATE, new DateRange(startUTC, endUTC));
commit(SET_PROJECT_CHARGES, charges);
commit(SET_PROJECT_USAGE_AND_CHARGES, usageAndCharges);
commit(SET_PRICE_SUMMARY, usageAndCharges);
commit(SET_CURRENT_ROLLUP_PRICE);
},
[GET_PROJECT_CHARGES_PREVIOUS_ROLLUP]: async function({commit}: any): Promise<void> {
[GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP]: async function({commit}: any): Promise<void> {
const now = new Date();
const startUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 1, 1, 0, 0));
const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 0, 23, 59, 59));
const charges: ProjectCharge[] = await api.projectsCharges(startUTC, endUTC);
const usageAndCharges: ProjectUsageAndCharges[] = await api.projectsUsageAndCharges(startUTC, endUTC);
commit(SET_DATE, new DateRange(startUTC, endUTC));
commit(SET_PROJECT_CHARGES, charges);
commit(SET_PROJECT_USAGE_AND_CHARGES, usageAndCharges);
commit(SET_PRICE_SUMMARY, usageAndCharges);
commit(SET_PREVIOUS_ROLLUP_PRICE);
},
},
getters: {
@ -229,6 +267,21 @@ export function makePaymentsModule(api: PaymentsApi): StoreModule<PaymentsState>
&& billingItem.status === BillingHistoryItemStatus.Completed;
}) || state.creditCards.length > 0;
},
isInvoiceForPreviousRollup: (state: PaymentsState): boolean => {
const now = new Date();
return state.billingHistory.some((billingItem: BillingHistoryItem) => {
if (now.getUTCMonth() === 0) {
return billingItem.type === BillingHistoryItemType.Invoice
&& billingItem.start.getUTCFullYear() === now.getUTCFullYear() - 1
&& billingItem.start.getUTCMonth() === 11;
}
return billingItem.type === BillingHistoryItemType.Invoice
&& billingItem.start.getUTCFullYear() === now.getUTCFullYear()
&& billingItem.start.getUTCMonth() === now.getUTCMonth() - 1;
});
},
},
};
}

View File

@ -21,9 +21,9 @@ export interface PaymentsApi {
getBalance(): Promise<number>;
/**
* projectsCharges returns how much money current user will be charged for each project which he owns.
* projectsUsagesAndCharges returns usage and how much money current user will be charged for each project which he owns.
*/
projectsCharges(since: Date, before: Date): Promise<ProjectCharge[]>;
projectsUsageAndCharges(since: Date, before: Date): Promise<ProjectUsageAndCharges[]>;
/**
* Add credit card
@ -177,9 +177,9 @@ class Amount {
}
/**
* ProjectCharge shows how much money current project will charge in the end of the month.
* ProjectUsageAndCharges shows usage and how much money current project will charge in the end of the month.
*/
export class ProjectCharge {
export class ProjectUsageAndCharges {
public constructor(
public since: Date = new Date(),
public before: Date = new Date(),

View File

@ -81,7 +81,8 @@ const {
GET_BALANCE,
GET_CREDIT_CARDS,
GET_BILLING_HISTORY,
GET_PROJECT_CHARGES_CURRENT_ROLLUP,
GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP,
GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP,
} = PAYMENTS_ACTIONS;
@Component({
@ -126,7 +127,8 @@ export default class DashboardArea extends Vue {
balance = await this.$store.dispatch(GET_BALANCE);
creditCards = await this.$store.dispatch(GET_CREDIT_CARDS);
await this.$store.dispatch(GET_BILLING_HISTORY);
await this.$store.dispatch(GET_PROJECT_CHARGES_CURRENT_ROLLUP);
await this.$store.dispatch(GET_PROJECT_USAGE_AND_CHARGES_PREVIOUS_ROLLUP);
await this.$store.dispatch(GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
} catch (error) {
await this.$notify.error(error.message);
}

View File

@ -52,21 +52,24 @@ export default class ForgotPassword extends Vue {
try {
await this.auth.forgotPassword(this.email);
await this.$notify.success('Please look for instructions at your email');
} catch (error) {
await this.$notify.error(error.message);
return;
}
await this.$notify.success('Please look for instructions at your email');
}
/**
* Changes location to Login route.
*/
public onBackToLoginClick(): void {
this.$router.push(RouteConfig.Login.path);
this.$router.push(RouteConfig.Login.path);
}
public onLogoClick(): void {
location.reload();
location.reload();
}
private validateFields(): boolean {

View File

@ -8,7 +8,7 @@ import EstimatedCostsAndCredits from '@/components/account/billing/estimatedCost
import { makePaymentsModule, PAYMENTS_MUTATIONS } from '@/store/modules/payments';
import { makeProjectsModule, PROJECTS_MUTATIONS } from '@/store/modules/projects';
import { makeUsersModule, USER_MUTATIONS } from '@/store/modules/users';
import { ProjectCharge } from '@/types/payments';
import { BillingHistoryItem, BillingHistoryItemType, ProjectUsageAndCharges } from '@/types/payments';
import { Project } from '@/types/projects';
import { User } from '@/types/users';
import { createLocalVue, mount } from '@vue/test-utils';
@ -34,10 +34,19 @@ const store = new Vuex.Store({ modules: { usersModule, projectsModule, paymentsM
const project = new Project('id', 'projectName', 'projectDescription', 'test', 'testOwnerId', true);
const user = new User('testOwnerId');
const date = new Date(1970, 1, 1);
const projectCharge = new ProjectCharge(date, date, 100, 100, 100, 'id', 100, 100, 100);
const projectCharge = new ProjectUsageAndCharges(date, date, 100, 100, 100, 'id', 100, 100, 100);
const {
SET_BALANCE,
CLEAR,
SET_BILLING_HISTORY,
SET_PROJECT_USAGE_AND_CHARGES,
SET_CURRENT_ROLLUP_PRICE,
SET_PREVIOUS_ROLLUP_PRICE,
SET_PRICE_SUMMARY,
} = PAYMENTS_MUTATIONS;
describe('EstimatedCostsAndCredits', () => {
it('renders correctly with project and no project charges', () => {
it('renders correctly with project and no project usage and charges', () => {
store.commit(USER_MUTATIONS.SET_USER, user);
store.commit(PROJECTS_MUTATIONS.ADD, project);
@ -49,9 +58,52 @@ describe('EstimatedCostsAndCredits', () => {
expect(wrapper).toMatchSnapshot();
});
it('renders correctly with project and project charges', () => {
store.commit(PAYMENTS_MUTATIONS.SET_BALANCE, 5500);
store.commit(PAYMENTS_MUTATIONS.SET_PROJECT_CHARGES, [projectCharge]);
it('renders correctly with project and project usage and charges', () => {
store.commit(SET_BALANCE, 5500);
store.commit(SET_PROJECT_USAGE_AND_CHARGES, [projectCharge]);
store.commit(SET_PRICE_SUMMARY, [projectCharge]);
store.commit(SET_CURRENT_ROLLUP_PRICE);
store.commit(SET_PREVIOUS_ROLLUP_PRICE);
const wrapper = mount(EstimatedCostsAndCredits, {
store,
localVue,
});
expect(wrapper).toMatchSnapshot();
});
it('renders correctly with project and project usage and charges with previous rollup invoice', () => {
const now = new Date();
let billingHistoryItem = new BillingHistoryItem('id', 'description', 300, 300, 'paid', 'test', new Date(now.getUTCFullYear(), now.getUTCMonth() - 1, 15), now, BillingHistoryItemType.Invoice);
if (now.getUTCMonth() === 0) {
billingHistoryItem = new BillingHistoryItem('id', 'description', 300, 300, 'paid', 'test', new Date(now.getUTCFullYear() - 1, 11, 15), now, BillingHistoryItemType.Invoice);
}
store.commit(CLEAR);
store.commit(SET_BALANCE, 600);
store.commit(SET_PROJECT_USAGE_AND_CHARGES, [projectCharge]);
store.commit(SET_PRICE_SUMMARY, [projectCharge]);
store.commit(SET_CURRENT_ROLLUP_PRICE);
store.commit(SET_BILLING_HISTORY, [billingHistoryItem]);
const wrapper = mount(EstimatedCostsAndCredits, {
store,
localVue,
});
expect(wrapper).toMatchSnapshot();
});
it('renders correctly with project and project usage and charges with price bigger than balance amount', () => {
store.commit(CLEAR);
store.commit(SET_BALANCE, 500);
store.commit(SET_PROJECT_USAGE_AND_CHARGES, [projectCharge]);
store.commit(SET_PRICE_SUMMARY, [projectCharge]);
store.commit(SET_CURRENT_ROLLUP_PRICE);
store.commit(SET_PREVIOUS_ROLLUP_PRICE);
store.commit(SET_BILLING_HISTORY, []);
const wrapper = mount(EstimatedCostsAndCredits, {
store,

View File

@ -3,11 +3,11 @@
import Vuex from 'vuex';
import UsageChargeItem from '@/components/account/billing/estimatedCostsAndCredits/UsageChargeItem.vue';
import UsageAndChargesItem from '@/components/account/billing/estimatedCostsAndCredits/UsageAndChargesItem.vue';
import { makePaymentsModule } from '@/store/modules/payments';
import { makeProjectsModule } from '@/store/modules/projects';
import { ProjectCharge } from '@/types/payments';
import { ProjectUsageAndCharges } from '@/types/payments';
import { Project } from '@/types/projects';
import { createLocalVue, shallowMount } from '@vue/test-utils';
@ -26,14 +26,14 @@ const paymentsApi = new PaymentsMock();
const paymentsModule = makePaymentsModule(paymentsApi);
const store = new Vuex.Store({ modules: { projectsModule, paymentsModule }});
describe('UsageChargeItem', () => {
describe('UsageAndChargesItem', () => {
const project = new Project('id', 'projectName', 'projectDescription', 'test', 'testOwnerId', true);
projectsApi.setMockProjects([project]);
const date = new Date(Date.UTC(1970, 1, 1));
const projectCharge = new ProjectCharge(date, date, 100, 100, 100, 'id', 100, 100, 100);
const projectCharge = new ProjectUsageAndCharges(date, date, 100, 100, 100, 'id', 100, 100, 100);
it('renders correctly', () => {
const wrapper = shallowMount(UsageChargeItem, {
const wrapper = shallowMount(UsageAndChargesItem, {
store,
localVue,
});
@ -42,7 +42,7 @@ describe('UsageChargeItem', () => {
});
it('toggling dropdown works correctly', async () => {
const wrapper = shallowMount(UsageChargeItem, {
const wrapper = shallowMount(UsageAndChargesItem, {
store,
localVue,
propsData: {
@ -50,11 +50,11 @@ describe('UsageChargeItem', () => {
},
});
await wrapper.find('.usage-charge-item-container__summary').trigger('click');
await wrapper.find('.usage-charges-item-container__summary').trigger('click');
expect(wrapper).toMatchSnapshot();
await wrapper.find('.usage-charge-item-container__summary').trigger('click');
await wrapper.find('.usage-charges-item-container__summary').trigger('click');
expect(wrapper).toMatchSnapshot();
});

View File

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EstimatedCostsAndCredits renders correctly with project and no project charges 1`] = `
exports[`EstimatedCostsAndCredits renders correctly with project and no project usage and charges 1`] = `
<div class="current-month-area">
<div class="current-month-area__title-area">
<h1 class="current-month-area__title-area__title">Estimated Costs for This Billing Period</h1> <span class="current-month-area__title-area__costs">USD $0.00</span>
@ -19,11 +19,16 @@ exports[`EstimatedCostsAndCredits renders correctly with project and no project
USD $0.00
</span>
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area"><span class="current-month-area__content__credits-area__title-area__title">Available Credits</span></div> <span class="current-month-area__content__credits-area__balance">
USD $0.00
</span>
</div>
</div>
</div>
`;
exports[`EstimatedCostsAndCredits renders correctly with project and project charges 1`] = `
exports[`EstimatedCostsAndCredits renders correctly with project and project usage and charges 1`] = `
<div class="current-month-area">
<div class="current-month-area__title-area">
<h1 class="current-month-area__title-area__title">Estimated Costs for This Billing Period</h1> <span class="current-month-area__title-area__costs">USD $3.00</span>
@ -35,9 +40,7 @@ exports[`EstimatedCostsAndCredits renders correctly with project and project cha
<div class="current-month-area__content__usage-charges__head__name-area">
<div class="current-month-area__content__usage-charges__head__name-area__image-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.363528 13.6272C-0.121176 13.1302 -0.121176 12.3243 0.363528 11.8273L5.07113 7L0.363528 2.17268C-0.121177 1.67565 -0.121177 0.869804 0.363528 0.372774C0.848232 -0.124258 1.63409 -0.124258 2.1188 0.372774L8.58166 7L2.1188 13.6272C1.63409 14.1243 0.848232 14.1243 0.363528 13.6272Z" fill="#2683FF"></path>
</svg>
<!---->
</div> <span class="current-month-area__content__usage-charges__head__name-area__title">Usage Charges</span>
</svg></div> <span class="current-month-area__content__usage-charges__head__name-area__title">Usage Charges</span>
</div> <span>Estimated total <span class="summary">USD $3.00</span></span>
</div>
<!---->
@ -47,6 +50,73 @@ exports[`EstimatedCostsAndCredits renders correctly with project and project cha
USD $55.00
</span>
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area"><span class="current-month-area__content__credits-area__title-area__title">Available Credits</span></div> <span class="current-month-area__content__credits-area__balance">
USD $49.00
</span>
</div>
</div>
</div>
`;
exports[`EstimatedCostsAndCredits renders correctly with project and project usage and charges with previous rollup invoice 1`] = `
<div class="current-month-area">
<div class="current-month-area__title-area">
<h1 class="current-month-area__title-area__title">Estimated Costs for This Billing Period</h1> <span class="current-month-area__title-area__costs">USD $3.00</span>
</div>
<div class="current-month-area__content">
<h2 class="current-month-area__content__title">DETAILS</h2>
<div class="current-month-area__content__usage-charges">
<div class="current-month-area__content__usage-charges__head">
<div class="current-month-area__content__usage-charges__head__name-area">
<div class="current-month-area__content__usage-charges__head__name-area__image-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.363528 13.6272C-0.121176 13.1302 -0.121176 12.3243 0.363528 11.8273L5.07113 7L0.363528 2.17268C-0.121177 1.67565 -0.121177 0.869804 0.363528 0.372774C0.848232 -0.124258 1.63409 -0.124258 2.1188 0.372774L8.58166 7L2.1188 13.6272C1.63409 14.1243 0.848232 14.1243 0.363528 13.6272Z" fill="#2683FF"></path>
</svg></div> <span class="current-month-area__content__usage-charges__head__name-area__title">Usage Charges</span>
</div> <span>Estimated total <span class="summary">USD $3.00</span></span>
</div>
<!---->
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area"><span class="current-month-area__content__credits-area__title-area__title">Earned Credits</span></div> <span class="current-month-area__content__credits-area__balance" style="color: rgb(0, 0, 0);">
USD $6.00
</span>
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area"><span class="current-month-area__content__credits-area__title-area__title">Available Credits</span></div> <span class="current-month-area__content__credits-area__balance">
USD $3.00
</span>
</div>
</div>
</div>
`;
exports[`EstimatedCostsAndCredits renders correctly with project and project usage and charges with price bigger than balance amount 1`] = `
<div class="current-month-area">
<div class="current-month-area__title-area">
<h1 class="current-month-area__title-area__title">Estimated Costs for This Billing Period</h1> <span class="current-month-area__title-area__costs">USD $3.00</span>
</div>
<div class="current-month-area__content">
<h2 class="current-month-area__content__title">DETAILS</h2>
<div class="current-month-area__content__usage-charges">
<div class="current-month-area__content__usage-charges__head">
<div class="current-month-area__content__usage-charges__head__name-area">
<div class="current-month-area__content__usage-charges__head__name-area__image-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.363528 13.6272C-0.121176 13.1302 -0.121176 12.3243 0.363528 11.8273L5.07113 7L0.363528 2.17268C-0.121177 1.67565 -0.121177 0.869804 0.363528 0.372774C0.848232 -0.124258 1.63409 -0.124258 2.1188 0.372774L8.58166 7L2.1188 13.6272C1.63409 14.1243 0.848232 14.1243 0.363528 13.6272Z" fill="#2683FF"></path>
</svg></div> <span class="current-month-area__content__usage-charges__head__name-area__title">Usage Charges</span>
</div> <span>Estimated total <span class="summary">USD $3.00</span></span>
</div>
<!---->
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area"><span class="current-month-area__content__credits-area__title-area__title">Earned Credits</span></div> <span class="current-month-area__content__credits-area__balance" style="color: rgb(0, 0, 0);">
USD $5.00
</span>
</div>
<div class="current-month-area__content__credits-area">
<div class="current-month-area__content__credits-area__title-area"><span class="current-month-area__content__credits-area__title-area__title">Available Credits</span></div> <span class="current-month-area__content__credits-area__balance">
USD $0.00
</span>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,64 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`UsageAndChargesItem renders correctly 1`] = `
<div class="usage-charges-item-container">
<div class="usage-charges-item-container__summary">
<div class="usage-charges-item-container__summary__name-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="usage-charges-item-container__summary__name-container__expand-image">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.328889 13.6272C-0.10963 13.1302 -0.10963 12.3243 0.328889 11.8273L4.58792 7L0.328889 2.17268C-0.10963 1.67565 -0.10963 0.869804 0.328889 0.372774C0.767408 -0.124258 1.47839 -0.124258 1.91691 0.372774L7.76396 7L1.91691 13.6272C1.47839 14.1243 0.767409 14.1243 0.328889 13.6272Z" fill="#2683FF"></path>
</svg>
<!----> <span></span></div>
<div class="usage-charges-item-container__summary__report-link">Advanced Report -&gt;</div>
</div>
<!---->
</div>
`;
exports[`UsageAndChargesItem toggling dropdown works correctly 1`] = `
<div class="usage-charges-item-container">
<div class="usage-charges-item-container__summary">
<div class="usage-charges-item-container__summary__name-container">
<!----> <svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg" class="usage-charges-item-container__summary__name-container__expand-image">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.372773 0.338888C0.869804 -0.112963 1.67565 -0.112963 2.17268 0.338888L7 4.72741L11.8273 0.338888C12.3243 -0.112963 13.1302 -0.112963 13.6272 0.338888C14.1243 0.790739 14.1243 1.52333 13.6272 1.97519L7 8L0.372773 1.97519C-0.124258 1.52333 -0.124258 0.790739 0.372773 0.338888Z" fill="#2683FF"></path>
</svg> <span></span></div>
<div class="usage-charges-item-container__summary__report-link">Advanced Report -&gt;</div>
</div>
<div class="usage-charges-item-container__detailed-info-container">
<div class="usage-charges-item-container__detailed-info-container__info-header"><span class="resource-header">RESOURCE</span> <span class="period-header">PERIOD</span> <span class="usage-header">USAGE</span> <span class="cost-header">COST</span></div>
<div class="usage-charges-item-container__detailed-info-container__content-area">
<div class="usage-charges-item-container__detailed-info-container__content-area__resource-container">
<p>Storage ($0.010 per Gigabyte-Month)</p>
<p>Egress ($0.045 per GB)</p>
<p>Objects ($0.0000022 per Object-Month)</p>
</div>
<div class="usage-charges-item-container__detailed-info-container__content-area__period-container">
<p>Feb 1 - Feb 1</p>
<p>Feb 1 - Feb 1</p>
<p>Feb 1 - Feb 1</p>
</div>
<div class="usage-charges-item-container__detailed-info-container__content-area__usage-container">
<p>0.00 Gigabyte-month</p>
<p>0.10 KB</p>
<p>0.14 Object-month</p>
</div>
<div class="usage-charges-item-container__detailed-info-container__content-area__cost-container">
<p class="price">USD $1.00</p>
<p class="price">USD $1.00</p>
<p class="price">USD $1.00</p>
</div>
</div> <span class="usage-charges-item-container__detailed-info-container__summary">USD $3.00</span>
</div>
</div>
`;
exports[`UsageAndChargesItem toggling dropdown works correctly 2`] = `
<div class="usage-charges-item-container">
<div class="usage-charges-item-container__summary">
<div class="usage-charges-item-container__summary__name-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="usage-charges-item-container__summary__name-container__expand-image">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.328889 13.6272C-0.10963 13.1302 -0.10963 12.3243 0.328889 11.8273L4.58792 7L0.328889 2.17268C-0.10963 1.67565 -0.10963 0.869804 0.328889 0.372774C0.767408 -0.124258 1.47839 -0.124258 1.91691 0.372774L7.76396 7L1.91691 13.6272C1.47839 14.1243 0.767409 14.1243 0.328889 13.6272Z" fill="#2683FF"></path>
</svg>
<!----> <span></span></div>
<div class="usage-charges-item-container__summary__report-link">Advanced Report -&gt;</div>
</div>
<!---->
</div>
`;

View File

@ -1,64 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`UsageChargeItem renders correctly 1`] = `
<div class="usage-charge-item-container">
<div class="usage-charge-item-container__summary">
<div class="usage-charge-item-container__summary__name-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="usage-charge-item-container__summary__name-container__expand-image">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.328889 13.6272C-0.10963 13.1302 -0.10963 12.3243 0.328889 11.8273L4.58792 7L0.328889 2.17268C-0.10963 1.67565 -0.10963 0.869804 0.328889 0.372774C0.767408 -0.124258 1.47839 -0.124258 1.91691 0.372774L7.76396 7L1.91691 13.6272C1.47839 14.1243 0.767409 14.1243 0.328889 13.6272Z" fill="#2683FF"></path>
</svg>
<!----> <span></span></div>
<div class="usage-charge-item-container__summary__report-link">Advanced Report -&gt;</div>
</div>
<!---->
</div>
`;
exports[`UsageChargeItem toggling dropdown works correctly 1`] = `
<div class="usage-charge-item-container">
<div class="usage-charge-item-container__summary">
<div class="usage-charge-item-container__summary__name-container">
<!----> <svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg" class="usage-charge-item-container__summary__name-container__expand-image">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.372773 0.338888C0.869804 -0.112963 1.67565 -0.112963 2.17268 0.338888L7 4.72741L11.8273 0.338888C12.3243 -0.112963 13.1302 -0.112963 13.6272 0.338888C14.1243 0.790739 14.1243 1.52333 13.6272 1.97519L7 8L0.372773 1.97519C-0.124258 1.52333 -0.124258 0.790739 0.372773 0.338888Z" fill="#2683FF"></path>
</svg> <span></span></div>
<div class="usage-charge-item-container__summary__report-link">Advanced Report -&gt;</div>
</div>
<div class="usage-charge-item-container__detailed-info-container">
<div class="usage-charge-item-container__detailed-info-container__info-header"><span class="resource-header">RESOURCE</span> <span class="period-header">PERIOD</span> <span class="usage-header">USAGE</span> <span class="cost-header">COST</span></div>
<div class="usage-charge-item-container__detailed-info-container__content-area">
<div class="usage-charge-item-container__detailed-info-container__content-area__resource-container">
<p>Storage ($0.010 per Gigabyte-Month)</p>
<p>Egress ($0.045 per GB)</p>
<p>Objects ($0.0000022 per Object-Month)</p>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area__period-container">
<p>Feb 1 - Feb 1</p>
<p>Feb 1 - Feb 1</p>
<p>Feb 1 - Feb 1</p>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area__usage-container">
<p>0.00 Gigabyte-month</p>
<p>0.10 KB</p>
<p>0.14 Object-month</p>
</div>
<div class="usage-charge-item-container__detailed-info-container__content-area__cost-container">
<p class="price">USD $1.00</p>
<p class="price">USD $1.00</p>
<p class="price">USD $1.00</p>
</div>
</div> <span class="usage-charge-item-container__detailed-info-container__summary">USD $3.00</span>
</div>
</div>
`;
exports[`UsageChargeItem toggling dropdown works correctly 2`] = `
<div class="usage-charge-item-container">
<div class="usage-charge-item-container__summary">
<div class="usage-charge-item-container__summary__name-container"><svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="usage-charge-item-container__summary__name-container__expand-image">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.328889 13.6272C-0.10963 13.1302 -0.10963 12.3243 0.328889 11.8273L4.58792 7L0.328889 2.17268C-0.10963 1.67565 -0.10963 0.869804 0.328889 0.372774C0.767408 -0.124258 1.47839 -0.124258 1.91691 0.372774L7.76396 7L1.91691 13.6272C1.47839 14.1243 0.767409 14.1243 0.328889 13.6272Z" fill="#2683FF"></path>
</svg>
<!----> <span></span></div>
<div class="usage-charge-item-container__summary__report-link">Advanced Report -&gt;</div>
</div>
<!---->
</div>
`;

View File

@ -1,7 +1,7 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectCharge, TokenDeposit } from '@/types/payments';
import { BillingHistoryItem, CreditCard, PaymentsApi, ProjectUsageAndCharges, TokenDeposit } from '@/types/payments';
/**
* Mock for PaymentsApi
@ -15,7 +15,7 @@ export class PaymentsMock implements PaymentsApi {
return Promise.resolve(0);
}
projectsCharges(): Promise<ProjectCharge[]> {
projectsUsageAndCharges(): Promise<ProjectUsageAndCharges[]> {
return Promise.resolve([]);
}