web/storagenode: period selection separation
Change-Id: I9f50f4bb9282410f9f3cc4124e71a7a631767460
This commit is contained in:
parent
d13b693b0c
commit
b6771d0c52
@ -4,8 +4,27 @@
|
||||
<template>
|
||||
<div class="estimation-container">
|
||||
<div class="estimation-container__header">
|
||||
<p class="estimation-container__header__title">Info & Estimation</p>
|
||||
<EstimationPeriodDropdown />
|
||||
<p class="estimation-container__header__title">Info & Estimation,
|
||||
<span class="estimation-container__header__period">{{ currentPeriod }}</span>
|
||||
</p>
|
||||
<div class="estimation-container__header__selection-area">
|
||||
<div
|
||||
class="estimation-container__header__selection-area__item"
|
||||
:class="{ active: isCurrentPeriod }"
|
||||
@click.stop="selectCurrentPeriod"
|
||||
>
|
||||
<p class="estimation-container__header__selection-area__item__label long-text">
|
||||
Current Period
|
||||
</p>
|
||||
<p class="estimation-container__header__selection-area__item__label short-text">
|
||||
Current Per.
|
||||
</p>
|
||||
</div>
|
||||
<EstimationPeriodDropdown
|
||||
class="estimation-container__header__selection-area__item"
|
||||
:class="{ active: !isCurrentPeriod }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="estimation-container__divider"></div>
|
||||
<div class="estimation-table-container" v-if="!isPayoutNoDataState">
|
||||
@ -95,14 +114,24 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import EstimationPeriodDropdown from '@/app/components/payments/EstimationPeriodDropdown.vue';
|
||||
|
||||
import { APPSTATE_ACTIONS } from '@/app/store/modules/appState';
|
||||
import {
|
||||
BANDWIDTH_DOWNLOAD_PRICE_PER_TB,
|
||||
BANDWIDTH_REPAIR_PRICE_PER_TB,
|
||||
DISK_SPACE_PRICE_PER_TB,
|
||||
DISK_SPACE_PRICE_PER_TB, PAYOUT_ACTIONS,
|
||||
} from '@/app/store/modules/payout';
|
||||
import { HeldInfo } from '@/app/types/payout';
|
||||
import { HeldInfo, PayoutInfoRange, PayoutPeriod } from '@/app/types/payout';
|
||||
import { formatBytes, TB } from '@/app/utils/converter';
|
||||
|
||||
/**
|
||||
* Holds all months names.
|
||||
*/
|
||||
const monthNames = [
|
||||
'January', 'February', 'March', 'April',
|
||||
'May', 'June', 'July', 'August',
|
||||
'September', 'October', 'November', 'December',
|
||||
];
|
||||
|
||||
/**
|
||||
* Describes table row data item.
|
||||
*/
|
||||
@ -125,6 +154,18 @@ class EstimationTableRow {
|
||||
export default class EstimationArea extends Vue {
|
||||
public now: Date = new Date();
|
||||
|
||||
/**
|
||||
* Returns formatted selected payout period.
|
||||
*/
|
||||
public get currentPeriod(): string {
|
||||
const start: PayoutPeriod = this.$store.state.payoutModule.periodRange.start;
|
||||
const end: PayoutPeriod = this.$store.state.payoutModule.periodRange.end;
|
||||
|
||||
return start && start.period !== end.period ?
|
||||
`${monthNames[start.month].slice(0, 3)} ${start.year} - ${monthNames[end.month].slice(0, 3)} ${end.year}`
|
||||
: `${monthNames[end.month].slice(0, 3)} ${end.year}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current month selected.
|
||||
*/
|
||||
@ -278,6 +319,21 @@ export default class EstimationArea extends Vue {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects current month as selected payout period.
|
||||
*/
|
||||
public async selectCurrentPeriod(): Promise<void> {
|
||||
const now = new Date();
|
||||
|
||||
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, false);
|
||||
await this.$store.dispatch(
|
||||
PAYOUT_ACTIONS.SET_PERIODS_RANGE, new PayoutInfoRange(
|
||||
null,
|
||||
new PayoutPeriod(now.getUTCFullYear(), now.getUTCMonth()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current month held amount based on currend day of month.
|
||||
*/
|
||||
@ -303,12 +359,50 @@ export default class EstimationArea extends Vue {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
|
||||
&__title {
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
color: var(--regular-text-color);
|
||||
}
|
||||
|
||||
&__period {
|
||||
color: #909bad;
|
||||
}
|
||||
|
||||
&__selection-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 100%;
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
border-bottom: 3px solid transparent;
|
||||
z-index: 102;
|
||||
|
||||
&__label {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: var(--regular-text-color);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-bottom: 3px solid var(--navigation-link-color);
|
||||
|
||||
&__label {
|
||||
font-size: 16px;
|
||||
color: var(--regular-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__total-held,
|
||||
@ -341,7 +435,6 @@ export default class EstimationArea extends Vue {
|
||||
&__divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin-top: 18px;
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
}
|
||||
@ -428,6 +521,10 @@ export default class EstimationArea extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
.short-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -493,6 +590,33 @@ export default class EstimationArea extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 870px) {
|
||||
|
||||
.estimation-container {
|
||||
|
||||
&__header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
height: auto;
|
||||
|
||||
&__selection-area {
|
||||
width: 100%;
|
||||
height: 41px;
|
||||
margin: 20px 0;
|
||||
|
||||
&__item {
|
||||
width: calc(50% - 40px);
|
||||
border-bottom: 3px solid #eaeaea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__divider {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
|
||||
.estimation-container {
|
||||
@ -514,4 +638,24 @@ export default class EstimationArea extends Vue {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 505px) {
|
||||
|
||||
.short-text {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.long-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 430px) {
|
||||
|
||||
.estimation-container__header__period {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
<template>
|
||||
<div class="period-container" @click.stop="openPeriodDropdown">
|
||||
<p class="period-container__label">{{ currentPeriod }}</p>
|
||||
<p class="period-container__label long-text">Custom Date Range</p>
|
||||
<p class="period-container__label short-text">Custom Range</p>
|
||||
<BlackArrowHide v-if="isCalendarShown" />
|
||||
<BlackArrowExpand v-else />
|
||||
<PayoutPeriodCalendar
|
||||
@ -23,16 +24,6 @@ import BlackArrowExpand from '@/../static/images/BlackArrowExpand.svg';
|
||||
import BlackArrowHide from '@/../static/images/BlackArrowHide.svg';
|
||||
|
||||
import { APPSTATE_ACTIONS } from '@/app/store/modules/appState';
|
||||
import { PayoutPeriod } from '@/app/types/payout';
|
||||
|
||||
/**
|
||||
* Holds all months names.
|
||||
*/
|
||||
const monthNames = [
|
||||
'January', 'February', 'March', 'April',
|
||||
'May', 'June', 'July', 'August',
|
||||
'September', 'October', 'November', 'December',
|
||||
];
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -42,18 +33,6 @@ const monthNames = [
|
||||
},
|
||||
})
|
||||
export default class EstimationPeriodDropdown extends Vue {
|
||||
/**
|
||||
* Returns formatted selected payout period.
|
||||
*/
|
||||
public get currentPeriod(): string {
|
||||
const start: PayoutPeriod = this.$store.state.payoutModule.periodRange.start;
|
||||
const end: PayoutPeriod = this.$store.state.payoutModule.periodRange.end;
|
||||
|
||||
return start && start.period !== end.period ?
|
||||
`${monthNames[start.month]}, ${start.year} - ${monthNames[end.month]}, ${end.year}`
|
||||
: `${monthNames[end.month]}, ${end.year}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if period selection calendar should appear.
|
||||
*/
|
||||
@ -92,7 +71,7 @@ export default class EstimationPeriodDropdown extends Vue {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: var(--month-label-color);
|
||||
color: var(--regular-text-color);
|
||||
}
|
||||
|
||||
&__calendar {
|
||||
@ -102,10 +81,37 @@ export default class EstimationPeriodDropdown extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
|
||||
.period-container__label {
|
||||
color: var(--navigation-link-color);
|
||||
}
|
||||
}
|
||||
|
||||
.arrow {
|
||||
|
||||
path {
|
||||
fill: var(--period-selection-arrow-color);
|
||||
}
|
||||
}
|
||||
|
||||
.short-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 505px) {
|
||||
|
||||
.period-container__label {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.short-text {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.long-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -108,37 +108,6 @@ export default class PayoutPeriodCalendar extends Vue {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: remove checks when buttons will be separated
|
||||
if (!this.secondSelectedMonth) {
|
||||
const now = new Date();
|
||||
if (this.firstSelectedMonth.year === now.getUTCFullYear() && this.firstSelectedMonth.index === now.getUTCMonth()) {
|
||||
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, false);
|
||||
await this.$store.dispatch(
|
||||
PAYOUT_ACTIONS.SET_PERIODS_RANGE, new PayoutInfoRange(
|
||||
null,
|
||||
new PayoutPeriod(this.firstSelectedMonth.year, this.firstSelectedMonth.index),
|
||||
),
|
||||
);
|
||||
|
||||
this.close();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.secondSelectedMonth && this.secondSelectedMonth.year === this.firstSelectedMonth.year && this.secondSelectedMonth.index === this.firstSelectedMonth.index) {
|
||||
await this.$store.dispatch(APPSTATE_ACTIONS.SET_NO_PAYOUT_DATA, false);
|
||||
await this.$store.dispatch(
|
||||
PAYOUT_ACTIONS.SET_PERIODS_RANGE, new PayoutInfoRange(
|
||||
null,
|
||||
new PayoutPeriod(this.firstSelectedMonth.year, this.firstSelectedMonth.index),
|
||||
),
|
||||
);
|
||||
|
||||
this.close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.secondSelectedMonth ? await this.$store.dispatch(
|
||||
PAYOUT_ACTIONS.SET_PERIODS_RANGE, new PayoutInfoRange(
|
||||
new PayoutPeriod(this.firstSelectedMonth.year, this.firstSelectedMonth.index),
|
||||
@ -183,8 +152,23 @@ export default class PayoutPeriodCalendar extends Vue {
|
||||
public selectAllTime(): void {
|
||||
const nodeStartedAt = this.$store.state.node.selectedSatellite.joinDate;
|
||||
|
||||
if (nodeStartedAt.getUTCMonth() === this.now.getUTCMonth() && nodeStartedAt.getUTCFullYear() === this.now.getUTCFullYear()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.firstSelectedMonth = new MonthButton(nodeStartedAt.getUTCFullYear(), nodeStartedAt.getUTCMonth());
|
||||
this.secondSelectedMonth = new MonthButton(this.now.getUTCFullYear(), this.now.getUTCMonth());
|
||||
this.secondSelectedMonth = this.now.getUTCMonth() === 0 ?
|
||||
new MonthButton(this.now.getUTCFullYear() - 1, 11)
|
||||
: new MonthButton(this.now.getUTCFullYear(), this.now.getUTCMonth() - 1);
|
||||
|
||||
if (
|
||||
this.firstSelectedMonth.year === this.secondSelectedMonth.year
|
||||
&& this.firstSelectedMonth.index === this.secondSelectedMonth.index
|
||||
) {
|
||||
this.secondSelectedMonth = null;
|
||||
this.checkMonth(this.firstSelectedMonth);
|
||||
}
|
||||
|
||||
this.updateMonthsSelection(true);
|
||||
this.updatePeriod();
|
||||
}
|
||||
@ -260,7 +244,21 @@ export default class PayoutPeriodCalendar extends Vue {
|
||||
* Marks all months between first and second selected as selected/unselected.
|
||||
*/
|
||||
private updateMonthsSelection(value: boolean): void {
|
||||
if (!this.secondSelectedMonth || !this.firstSelectedMonth) return;
|
||||
if (!this.firstSelectedMonth) return;
|
||||
|
||||
if (!this.secondSelectedMonth) {
|
||||
const selectedMonth = this.displayedMonths[this.firstSelectedMonth.year].find(month => {
|
||||
if (this.firstSelectedMonth) {
|
||||
return month.index === this.firstSelectedMonth.index;
|
||||
}
|
||||
});
|
||||
|
||||
if (selectedMonth) {
|
||||
selectedMonth.selected = value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = this.firstSelectedMonth.year; i <= this.secondSelectedMonth.year; i++) {
|
||||
if (!this.displayedMonths[i]) {
|
||||
@ -300,9 +298,9 @@ export default class PayoutPeriodCalendar extends Vue {
|
||||
const notBeforeNodeStart =
|
||||
nodeStartedAt.getUTCFullYear() < year
|
||||
|| (nodeStartedAt.getUTCFullYear() === year && nodeStartedAt.getUTCMonth() <= i);
|
||||
const inFuture = isCurrentYear && i > nowMonth;
|
||||
const inFutureOrCurrent = isCurrentYear && i >= nowMonth;
|
||||
|
||||
const isMonthActive = notBeforeNodeStart && !inFuture;
|
||||
const isMonthActive = notBeforeNodeStart && !inFutureOrCurrent;
|
||||
months.push(new MonthButton(year, i, isMonthActive, false));
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import Vue, { VNode } from 'vue';
|
||||
import { DirectiveBinding } from 'vue/types/options';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import EstimationPeriodDropdown from '@/app/components/payments/EstimationPeriodDropdown.vue';
|
||||
|
||||
import { APPSTATE_ACTIONS, appStateModule } from '@/app/store/modules/appState';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
Vue.directive('click-outside', {
|
||||
bind: (): void => { return; },
|
||||
unbind: (): void => { return; },
|
||||
});
|
||||
|
||||
const store = new Vuex.Store({ modules: { appStateModule }});
|
||||
|
||||
describe('DiskStatChart', (): void => {
|
||||
it('renders correctly', (): void => {
|
||||
const wrapper = shallowMount(EstimationPeriodDropdown, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly with calendar', async (): Promise<void> => {
|
||||
const wrapper = shallowMount(EstimationPeriodDropdown, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
await store.dispatch(APPSTATE_ACTIONS.TOGGLE_PAYOUT_CALENDAR, true);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('opens calendar on click', (): void => {
|
||||
const wrapper = shallowMount(EstimationPeriodDropdown, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
wrapper.find('.period-container').trigger('click');
|
||||
|
||||
expect(wrapper.find('.period-container__calendar').exists()).toBe(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,19 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DiskStatChart renders correctly 1`] = `
|
||||
<div class="period-container">
|
||||
<p class="period-container__label long-text">Custom Date Range</p>
|
||||
<p class="period-container__label short-text">Custom Range</p>
|
||||
<blackarrowexpand-stub></blackarrowexpand-stub>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`DiskStatChart renders correctly with calendar 1`] = `
|
||||
<div class="period-container">
|
||||
<p class="period-container__label long-text">Custom Date Range</p>
|
||||
<p class="period-container__label short-text">Custom Range</p>
|
||||
<blackarrowhide-stub></blackarrowhide-stub>
|
||||
<payoutperiodcalendar-stub class="period-container__calendar"></payoutperiodcalendar-stub>
|
||||
</div>
|
||||
`;
|
Loading…
Reference in New Issue
Block a user