separate pages: overview and send.

apexcharts library inserted.
example charts created: lienen and bar charts.
example charts inserted
This commit is contained in:
ogerly 2021-10-13 16:13:28 +02:00
parent 8b45d0da58
commit db1124da3f
24 changed files with 715 additions and 202 deletions

View File

@ -18,6 +18,7 @@
"@babel/preset-env": "^7.13.12", "@babel/preset-env": "^7.13.12",
"@vue/cli-plugin-unit-jest": "^4.5.12", "@vue/cli-plugin-unit-jest": "^4.5.12",
"@vue/test-utils": "^1.1.3", "@vue/test-utils": "^1.1.3",
"apexcharts": "^3.28.3",
"apollo-boost": "^0.4.9", "apollo-boost": "^0.4.9",
"axios": "^0.21.1", "axios": "^0.21.1",
"babel-core": "^7.0.0-bridge.0", "babel-core": "^7.0.0-bridge.0",
@ -61,6 +62,7 @@
"sweetalert2": "^9.5.4", "sweetalert2": "^9.5.4",
"vee-validate": "^3.4.5", "vee-validate": "^3.4.5",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-apexcharts": "^1.6.2",
"vue-apollo": "^3.0.7", "vue-apollo": "^3.0.7",
"vue-bootstrap-typeahead": "^0.2.6", "vue-bootstrap-typeahead": "^0.2.6",
"vue-cli-plugin-i18n": "^1.0.1", "vue-cli-plugin-i18n": "^1.0.1",

View File

@ -0,0 +1,112 @@
<template>
<div class="appChartExample">
<apexchart width="100%" height="400" type="line" :options="chartOptions" :series="series" />
<apexchart
width="100%"
height="150"
type="area"
:options="chartOptionsMinimap"
:series="series"
/>
<div></div>
</div>
</template>
<script>
import { series } from './series.js'
export default {
data: function () {
const chartId = 'priceHistoryChart' + Date.now()
const chartIdMinimap = 'priceHistoryChartMinimap' + Date.now()
const dateFrom = new Date('2018-09-26')
const dateTo = new Date('2018-10-01')
const chartOptions = {
chart: {
background: '#efe',
id: chartId,
animations: {
enabled: false,
},
toolbar: {
autoSelected: 'pan',
show: false,
},
},
legend: {
position: 'right',
},
stroke: {
curve: 'smooth',
width: [4],
dashArray: [10],
},
tooltip: {
followCursor: true,
x: {
show: false,
},
},
xaxis: {
type: 'datetime',
},
}
const chartOptionsMinimap = {
chart: {
id: chartIdMinimap,
animations: {
enabled: false,
},
brush: {
enabled: true,
target: chartId,
},
selection: {
xaxis: {
min: dateFrom.getTime(),
max: dateTo.getTime(),
},
},
type: 'line',
},
fill: {
gradient: {
enabled: true,
opacityFrom: 0.91,
opacityTo: 0.1,
},
},
legend: {
show: false,
},
xaxis: {
type: 'datetime',
},
}
return {
chartOptions,
chartOptionsMinimap,
series,
}
},
methods: {
updateChart() {
this.chartOptionsMinimap = {
chart: {
foreColor: '#' + Math.floor(Math.random() * 16777215).toString(16),
selection: {
xaxis: {
min: new Date('2018-09-28').getTime(),
max: new Date('2018-09-30').getTime(),
},
},
},
}
},
},
}
</script>

View File

@ -0,0 +1,224 @@
export const series = [
{
name: 'obb.docker',
data: [
{
x: '2018-09-25',
y: 900,
},
{
x: '2018-09-26',
y: 900,
},
{
x: '2018-09-27',
y: 900,
},
{
x: '2018-09-28',
y: 900,
},
{
x: '2018-09-29',
y: 900,
},
{
x: '2018-09-30',
y: 900,
},
{
x: '2018-10-01',
y: 900,
},
{
x: '2018-10-02',
y: 1125,
},
],
},
{
name: 'filato.dk',
data: [
{
x: '2018-09-25',
y: 1251.45,
},
{
x: '2018-09-26',
y: 984.94,
},
{
x: '2018-09-27',
y: 1170.34,
},
{
x: '2018-09-28',
y: 1193.51,
},
{
x: '2018-09-29',
y: 1251.45,
},
{
x: '2018-09-30',
y: 1147.16,
},
{
x: '2018-10-01',
y: 1263.04,
},
{
x: '2018-10-02',
y: 1158.75,
},
],
},
{
name: 'rito.dk',
data: [
{
x: '2018-09-25',
y: 1193.06,
},
{
x: '2018-09-26',
y: 1193.06,
},
{
x: '2018-09-27',
y: 1068.08,
},
{
x: '2018-09-28',
y: 909,
},
{
x: '2018-09-29',
y: 965.81,
},
{
x: '2018-09-30',
y: 965.81,
},
{
x: '2018-10-01',
y: 1022.63,
},
{
x: '2018-10-02',
y: 1136.25,
},
],
},
{
name: 'fruhyasinth.dk',
data: [
{
x: '2018-09-25',
y: 1064.7,
},
{
x: '2018-09-26',
y: 1146.6,
},
{
x: '2018-09-27',
y: 1216.8,
},
{
x: '2018-09-28',
y: 959.4,
},
{
x: '2018-09-29',
y: 1193.4,
},
{
x: '2018-09-30',
y: 1017.9,
},
{
x: '2018-10-01',
y: 1275.3,
},
{
x: '2018-10-02',
y: 1170,
},
],
},
{
name: 'bilka.dk',
data: [
{
x: '2018-09-25',
y: 973.35,
},
{
x: '2018-09-26',
y: 1147.16,
},
{
x: '2018-09-27',
y: 1263.04,
},
{
x: '2018-09-28',
y: 927,
},
{
x: '2018-09-29',
y: 950.18,
},
{
x: '2018-09-30',
y: 1123.99,
},
{
x: '2018-10-01',
y: 1158.75,
},
{
x: '2018-10-02',
y: 1158.75,
},
],
},
{
name: 'hobbii.dk',
data: [
{
x: '2018-09-25',
y: 963.9,
},
{
x: '2018-09-26',
y: 1136.03,
},
{
x: '2018-09-27',
y: 1216.35,
},
{
x: '2018-09-28',
y: 1067.18,
},
{
x: '2018-09-29',
y: 952.43,
},
{
x: '2018-09-30',
y: 929.48,
},
{
x: '2018-10-01',
y: 1204.88,
},
{
x: '2018-10-02',
y: 1147.5,
},
],
},
]

View File

@ -4,6 +4,9 @@ import VueI18n from 'vue-i18n'
import en from 'vee-validate/dist/locale/en' import en from 'vee-validate/dist/locale/en'
import de from 'vee-validate/dist/locale/de' import de from 'vee-validate/dist/locale/de'
import enCharts from 'apexcharts/dist/locales/en'
import deCharts from 'apexcharts/dist/locales/de'
Vue.use(VueI18n) Vue.use(VueI18n)
function loadLocaleMessages() { function loadLocaleMessages() {
@ -17,12 +20,14 @@ function loadLocaleMessages() {
if (locale === 'de') { if (locale === 'de') {
messages[locale] = { messages[locale] = {
validations: de, validations: de,
charts: deCharts,
...messages[locale], ...messages[locale],
} }
} }
if (locale === 'en') { if (locale === 'en') {
messages[locale] = { messages[locale] = {
validations: en, validations: en,
charts: enCharts,
...messages[locale], ...messages[locale],
} }
} }

View File

@ -102,8 +102,8 @@
"logout": "Abmelden", "logout": "Abmelden",
"members_area": "Mitgliederbereich", "members_area": "Mitgliederbereich",
"message": "hallo gradido !!", "message": "hallo gradido !!",
"privacy_policy": "Datenschutzerklärung",
"overview": "Übersicht", "overview": "Übersicht",
"privacy_policy": "Datenschutzerklärung",
"send": "Senden", "send": "Senden",
"settings": { "settings": {
"coinanimation": { "coinanimation": {

View File

@ -102,8 +102,8 @@
"logout": "Logout", "logout": "Logout",
"members_area": "Member's area", "members_area": "Member's area",
"message": "hello gradido !!", "message": "hello gradido !!",
"privacy_policy": "Privacy policy",
"overview": "Overview", "overview": "Overview",
"privacy_policy": "Privacy policy",
"send": "Send", "send": "Send",
"settings": { "settings": {
"coinanimation": { "coinanimation": {

View File

@ -6,7 +6,7 @@ import { loadAllRules } from './validation-rules'
import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost'
import VueApollo from 'vue-apollo' import VueApollo from 'vue-apollo'
import CONFIG from './config' import CONFIG from './config'
import VueCharts from 'vue-chartjs' import VueApexCharts from 'vue-apexcharts'
import { store } from './store/store' import { store } from './store/store'
import router from './routes/router' import router from './routes/router'
@ -57,6 +57,9 @@ router.beforeEach((to, from, next) => {
} }
}) })
Vue.use(VueApexCharts)
Vue.component('apexchart', VueApexCharts)
/* eslint-disable no-new */ /* eslint-disable no-new */
new Vue({ new Vue({
el: '#app', el: '#app',
@ -64,6 +67,5 @@ new Vue({
store, store,
i18n, i18n,
apolloProvider, apolloProvider,
VueCharts,
render: (h) => h(App), render: (h) => h(App),
}) })

View File

@ -84,33 +84,43 @@ describe('DashboardLayoutGdd', () => {
navbar = wrapper.findAll('ul.navbar-nav').at(0) navbar = wrapper.findAll('ul.navbar-nav').at(0)
}) })
it('has three items in the navbar', () => { it('has four items in the navbar', () => {
expect(navbar.findAll('ul > a')).toHaveLength(3) expect(navbar.findAll('ul > a')).toHaveLength(4)
}) })
it('has first item "send" in navbar', () => { it('has first item "overview" in navbar', () => {
expect(navbar.findAll('ul > a').at(0).text()).toEqual('send') expect(navbar.findAll('ul > a').at(0).text()).toEqual('overview')
}) })
it('has first item "send" linked to overview in navbar', () => { it('has first item "overview" linked to overview in navbar', () => {
navbar.findAll('ul > a').at(0).trigger('click') navbar.findAll('ul > a').at(0).trigger('click')
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/overview') expect(wrapper.findComponent(RouterLinkStub).props(0).to).toBe('/overview')
}) })
it('has second item "transactions" in navbar', () => { it('has second item "send" in navbar', () => {
expect(navbar.findAll('ul > a').at(1).text()).toEqual('transactions') expect(navbar.findAll('ul > a').at(1).text()).toEqual('send')
}) })
it('has second item "transactions" linked to transactions in navbar', async () => { it('has second item "send" linked to sendoverview in navbar', () => {
expect(wrapper.findAll('a').at(3).attributes('href')).toBe('/transactions') navbar.findAll('ul > a').at(1).trigger('click')
expect(wrapper.findAll('a').at(3).attributes('href')).toBe('/send')
}) })
it('has three items in the navbar', () => { it('has three item "transactions" in navbar', () => {
expect(navbar.findAll('ul > a')).toHaveLength(3) expect(navbar.findAll('ul > a').at(2).text()).toEqual('transactions')
})
it('has three item "transactions" linked to transactions in navbar', async () => {
navbar.findAll('ul > a').at(2).trigger('click')
expect(wrapper.findAll('a').at(5).attributes('href')).toBe('/transactions')
})
it('has three item "profil" in navbar', () => {
expect(navbar.findAll('ul > a').at(3).text()).toEqual('site.navbar.my-profil')
}) })
it('has third item "My profile" linked to profile in navbar', async () => { it('has third item "My profile" linked to profile in navbar', async () => {
expect(wrapper.findAll('a').at(5).attributes('href')).toBe('/profile') expect(wrapper.findAll('a').at(7).attributes('href')).toBe('/profile')
}) })
it('has a link to the members area', () => { it('has a link to the members area', () => {

View File

@ -1,9 +1,6 @@
import { mount } from '@vue/test-utils' import { mount } from '@vue/test-utils'
import AccountOverview from './AccountOverview' import AccountOverview from './AccountOverview'
const sendMock = jest.fn()
sendMock.mockResolvedValue('success')
const localVue = global.localVue const localVue = global.localVue
window.scrollTo = jest.fn() window.scrollTo = jest.fn()
@ -11,26 +8,17 @@ window.scrollTo = jest.fn()
describe('AccountOverview', () => { describe('AccountOverview', () => {
let wrapper let wrapper
const propsData = {
balance: 123.45,
transactionCount: 1,
}
const mocks = { const mocks = {
$t: jest.fn((t) => t), $t: jest.fn((t) => t),
$n: jest.fn((n) => String(n)), $n: jest.fn(),
$store: {
state: {
email: 'sender@example.org',
},
},
$apollo: {
mutate: sendMock,
},
} }
const Wrapper = () => { const Wrapper = () => {
return mount(AccountOverview, { localVue, mocks, propsData }) return mount(AccountOverview, {
localVue,
mocks,
stubs: ['apexchart'],
})
} }
describe('mount', () => { describe('mount', () => {
@ -42,94 +30,8 @@ describe('AccountOverview', () => {
expect(wrapper.find('div.gdd-status').exists()).toBeTruthy() expect(wrapper.find('div.gdd-status').exists()).toBeTruthy()
}) })
it('has a send field', () => {
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
})
it('has a transactions table', () => { it('has a transactions table', () => {
expect(wrapper.find('div.gdd-transaction-list').exists()).toBeTruthy() expect(wrapper.find('div.gdd-transaction-list').exists()).toBeTruthy()
}) })
describe('transaction form', () => {
it('steps forward in the dialog', async () => {
await wrapper.findComponent({ name: 'TransactionForm' }).vm.$emit('set-transaction', {
email: 'user@example.org',
amount: 23.45,
memo: 'Make the best of it!',
})
expect(wrapper.findComponent({ name: 'TransactionConfirmation' }).exists()).toBeTruthy()
})
})
describe('confirm transaction', () => {
beforeEach(() => {
wrapper.setData({
currentTransactionStep: 1,
transactionData: {
email: 'user@example.org',
amount: 23.45,
memo: 'Make the best of it!',
},
})
})
it('resets the transaction process when on-reset is emitted', async () => {
await wrapper.findComponent({ name: 'TransactionConfirmation' }).vm.$emit('on-reset')
expect(wrapper.findComponent({ name: 'TransactionForm' }).exists()).toBeTruthy()
expect(wrapper.vm.transactionData).toEqual({
email: '',
amount: 0,
memo: '',
})
})
describe('transaction is confirmed and server response is success', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper
.findComponent({ name: 'TransactionConfirmation' })
.vm.$emit('send-transaction')
})
it('calls the API when send-transaction is emitted', async () => {
expect(sendMock).toBeCalledWith(
expect.objectContaining({
variables: {
email: 'user@example.org',
amount: 23.45,
memo: 'Make the best of it!',
},
}),
)
})
it('emits update-balance', () => {
expect(wrapper.emitted('update-balance')).toBeTruthy()
expect(wrapper.emitted('update-balance')).toEqual([[23.45]])
})
it('shows the succes page', () => {
expect(wrapper.find('div.card-body').text()).toContain('form.send_transaction_success')
})
})
describe('transaction is confirmed and server response is error', () => {
beforeEach(async () => {
jest.clearAllMocks()
sendMock.mockRejectedValue({ message: 'receiver not found' })
await wrapper
.findComponent({ name: 'TransactionConfirmation' })
.vm.$emit('send-transaction')
})
it('shows the error page', () => {
expect(wrapper.find('div.card-body').text()).toContain('form.send_transaction_error')
})
it('shows recipient not found', () => {
expect(wrapper.text()).toContain('transaction.receiverNotFound')
})
})
})
}) })
}) })

View File

@ -1,29 +1,56 @@
<template> <template>
<div> <div>
<b-container fluid> <b-container fluid>
<gdd-status <b-row>
v-if="showContext" <b-col class="col-6">
:pending="pending" <b-row>
:balance="balance" <b-col class="col-11 bg-gray text-white p-3">
:gdt-balance="GdtBalance" <gdd-status
/> v-if="showContext"
:pending="pending"
:balance="balance"
:gdt-balance="GdtBalance"
:gdt="false"
/>
</b-col>
</b-row>
</b-col>
<b-col class="col-6 text-right">
<b-row>
<b-col class="bg-white text-gray p-3">
<gdd-status
v-if="showContext"
:pending="pending"
:balance="balance"
:gdt-balance="GdtBalance"
:gdd="false"
/>
</b-col>
</b-row>
</b-col>
</b-row>
<br /> <br />
<hr>
GDD Statistik
<hr>
GDT Statistik
<b-row>
<b-col class="col-12 col-md-6">
GDD Bar
<div>
<apexchart type="bar" :options="chartOptions" :series="series"></apexchart>
</div>
</b-col>
<b-col class="col-12 col-md-6">
GDD Line
<div>
<apexchart type="line" :options="chartOptions" :series="series"></apexchart>
</div>
</b-col>
</b-row>
<hr />
<template #transaction-form> <template #transaction-form>
<transaction-form :balance="balance" @set-transaction="setTransaction"></transaction-form> <transaction-form :balance="balance" @set-transaction="setTransaction"></transaction-form>
</template> </template>
<hr />
<gdd-transaction-list <gdd-transaction-list
v-if="showContext" v-if="showContext"
:transactions="transactions" :transactions="transactions"
@ -33,43 +60,58 @@
@update-transactions="updateTransactions" @update-transactions="updateTransactions"
/> />
<gdd-transaction-list-footer v-if="showContext" :count="transactionCount" /> <gdd-transaction-list-footer v-if="showContext" :count="transactionCount" />
<hr>
UserAccount Statistik
</b-container> </b-container>
<hr />
example
<chart-example />
</div> </div>
</template> </template>
<script> <script>
import GddStatus from './GddGdtStatus.vue'
import GddStatus from './AccountOverview/GddStatus.vue'
import GddTransactionList from './AccountOverview/GddTransactionList.vue' import GddTransactionList from './AccountOverview/GddTransactionList.vue'
import GddTransactionListFooter from './AccountOverview/GddTransactionListFooter.vue' import GddTransactionListFooter from './AccountOverview/GddTransactionListFooter.vue'
import ChartExample from '../../components/charts/ChartExample.vue'
const EMPTY_TRANSACTION_DATA = {
email: '',
amount: 0,
memo: '',
}
export default { export default {
name: 'Overview', name: 'Overview',
components: { components: {
GddStatus, GddStatus,
GddTransactionList, GddTransactionList,
GddTransactionListFooter, GddTransactionListFooter,
ChartExample,
}, },
data() { data() {
return { return {
timestamp: Date.now(), timestamp: Date.now(),
transactionData: { ...EMPTY_TRANSACTION_DATA },
error: false, error: false,
errorResult: '', errorResult: '',
currentTransactionStep: 0, currentTransactionStep: 0,
loading: false, loading: false,
datacollectionGdd: null, datacollectionGdd: null,
datacollectionGdt: null, datacollectionGdt: null,
chartOptions: {
chart: {
id: 'vuechart-example',
},
xaxis: {
categories: ['Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt'],
},
},
series: [
{
name: 'Einnahmen',
data: [30, 40, 35, 50, 49, 60, 70, 91],
},
{
name: 'Ausgaben',
data: [20, 10, 45, 60, 59, 30, 50, 81],
},
{
name: 'geschöpft',
data: [1000, 500, 700, 1000, 800, 500, 1000, 810],
},
],
} }
}, },
props: { props: {
@ -91,19 +133,16 @@ export default {
}, },
methods: { methods: {
setTransaction(data) { setTransaction(data) {
this.transactionData = { ...data }
this.currentTransactionStep = 1 this.currentTransactionStep = 1
}, },
onReset() { onReset() {
this.transactionData = { ...EMPTY_TRANSACTION_DATA }
this.currentTransactionStep = 0 this.currentTransactionStep = 0
}, },
updateTransactions(pagination) { updateTransactions(pagination) {
this.$emit('update-transactions', pagination) this.$emit('update-transactions', pagination)
}, },
}, },
} }
</script> </script>

View File

@ -1,30 +0,0 @@
<template>
<div class="gdd-status">
<b-row>
<b-col class="p-0">
<b-card class="p-0" style="background-color: #ebebeba3 !important">
{{ pending ? '—' : $n(balance, 'decimal') }} GDD
</b-card>
</b-col>
<b-col class="pr-0">
<b-card class="p-0 text-right" style="background-color: #ebebeba3 !important">
{{ pending ? '—' : $n(GdtBalance, 'decimal') }} GDT
</b-card>
</b-col>
</b-row>
</div>
</template>
<script>
export default {
name: 'GddStatus',
props: {
balance: { type: Number, default: 0 },
GdtBalance: { type: Number, default: 0 },
pending: {
type: Boolean,
default: true,
},
},
}
</script>

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils' import { mount } from '@vue/test-utils'
import GddStatus from './GddStatus' import GddStatus from './GddGdtStatus'
const localVue = global.localVue const localVue = global.localVue
@ -26,11 +26,11 @@ describe('GddStatus', () => {
describe('balance is loading', () => { describe('balance is loading', () => {
it('it displays em-dash as the ammount of GDD', () => { it('it displays em-dash as the ammount of GDD', () => {
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('— GDD') expect(wrapper.find('div.gdd-status-gdd').text()).toEqual('— GDD')
}) })
it('it displays em-dash as the ammount of GDT', () => { it('it displays em-dash as the ammount of GDT', () => {
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('— GDT') expect(wrapper.find('div.gdd-status-gdt').text()).toEqual('— GDT')
}) })
}) })
@ -42,11 +42,11 @@ describe('GddStatus', () => {
}) })
it('it displays the ammount of GDD', () => { it('it displays the ammount of GDD', () => {
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD') expect(wrapper.find('div.gdd-status-gdd').text()).toEqual('1234 GDD')
}) })
it('it displays the ammount of GDT', () => { it('it displays the ammount of GDT', () => {
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT') expect(wrapper.find('div.gdd-status-gdt').text()).toEqual('9876 GDT')
}) })
}) })
}) })

View File

@ -0,0 +1,32 @@
<template>
<div class="gdd-status">
<div class="p-0 gdd-status-gdd" v-if="gdd">
{{ pending ? '—' : $n(balance, 'decimal') }} GDD
</div>
<div :class="gdd ? 'p-0 text-right gdd-status-gdt' : 'p-0 gdd-status-gdt'" v-if="gdt">
{{ pending ? '—' : $n(GdtBalance, 'decimal') }} GDT
</div>
</div>
</template>
<script>
export default {
name: 'GddStatus',
props: {
balance: { type: Number, default: 0 },
GdtBalance: { type: Number, default: 0 },
pending: {
type: Boolean,
default: true,
},
gdd: {
type: Boolean,
default: true,
},
gdt: {
type: Boolean,
default: true,
},
},
}
</script>

View File

@ -0,0 +1,135 @@
import { mount } from '@vue/test-utils'
import SendOverview from './SendOverview'
const sendMock = jest.fn()
sendMock.mockResolvedValue('success')
const localVue = global.localVue
// window.scrollTo = jest.fn()
describe('SendOverview', () => {
let wrapper
const propsData = {
balance: 123.45,
transactionCount: 1,
}
const mocks = {
$t: jest.fn((t) => t),
$n: jest.fn((n) => String(n)),
$store: {
state: {
email: 'sender@example.org',
},
},
$apollo: {
mutate: sendMock,
},
}
const Wrapper = () => {
return mount(SendOverview, { localVue, mocks, propsData })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('has a status GDD line', () => {
expect(wrapper.find('div.gdd-status-gdd').exists()).toBeTruthy()
})
it('has a send field', () => {
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
})
// it('has a transactions table', () => {
// expect(wrapper.find('div.gdd-transaction-list').exists()).toBeTruthy()
// })
describe('transaction form', () => {
it('steps forward in the dialog', async () => {
await wrapper.findComponent({ name: 'TransactionForm' }).vm.$emit('set-transaction', {
email: 'user@example.org',
amount: 23.45,
memo: 'Make the best of it!',
})
expect(wrapper.findComponent({ name: 'TransactionConfirmation' }).exists()).toBeTruthy()
})
})
describe('confirm transaction', () => {
beforeEach(() => {
wrapper.setData({
currentTransactionStep: 1,
transactionData: {
email: 'user@example.org',
amount: 23.45,
memo: 'Make the best of it!',
},
})
})
it('resets the transaction process when on-reset is emitted', async () => {
await wrapper.findComponent({ name: 'TransactionConfirmation' }).vm.$emit('on-reset')
expect(wrapper.findComponent({ name: 'TransactionForm' }).exists()).toBeTruthy()
expect(wrapper.vm.transactionData).toEqual({
email: '',
amount: 0,
memo: '',
})
})
describe('transaction is confirmed and server response is success', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper
.findComponent({ name: 'TransactionConfirmation' })
.vm.$emit('send-transaction')
})
it('calls the API when send-transaction is emitted', async () => {
expect(sendMock).toBeCalledWith(
expect.objectContaining({
variables: {
email: 'user@example.org',
amount: 23.45,
memo: 'Make the best of it!',
},
}),
)
})
it('emits update-balance', () => {
expect(wrapper.emitted('update-balance')).toBeTruthy()
expect(wrapper.emitted('update-balance')).toEqual([[23.45]])
})
it('shows the succes page', () => {
expect(wrapper.find('div.card-body').text()).toContain('form.send_transaction_success')
})
})
describe('transaction is confirmed and server response is error', () => {
beforeEach(async () => {
jest.clearAllMocks()
sendMock.mockRejectedValue({ message: 'receiver not found' })
await wrapper
.findComponent({ name: 'TransactionConfirmation' })
.vm.$emit('send-transaction')
})
it('shows the error page', () => {
expect(wrapper.find('div.card-body').text()).toContain('form.send_transaction_error')
})
it('shows recipient not found', () => {
expect(wrapper.text()).toContain('transaction.receiverNotFound')
})
})
})
})
})

View File

@ -1,12 +1,18 @@
<template> <template>
<div> <div>
<b-container fluid> <b-container fluid>
<gdd-status <b-row>
v-if="showContext" <b-col class="bg-gray text-white text-center p-3">
:pending="pending" <gdd-status
:balance="balance" v-if="showContext"
:gdt-balance="GdtBalance" :pending="pending"
/> :balance="balance"
:gdt-balance="GdtBalance"
:gdt="false"
/>
</b-col>
</b-row>
<br /> <br />
<gdd-send :currentTransactionStep="currentTransactionStep"> <gdd-send :currentTransactionStep="currentTransactionStep">
<template #transaction-form> <template #transaction-form>
@ -35,12 +41,12 @@
</div> </div>
</template> </template>
<script> <script>
import GddStatus from './AccountOverview/GddStatus.vue' import GddStatus from './GddGdtStatus.vue'
import GddSend from './AccountOverview/GddSend.vue' import GddSend from './SendOverview/GddSend.vue'
import TransactionForm from './AccountOverview/GddSend/TransactionForm.vue' import TransactionForm from './SendOverview/GddSend/TransactionForm.vue'
import TransactionConfirmation from './AccountOverview/GddSend/TransactionConfirmation.vue' import TransactionConfirmation from './SendOverview/GddSend/TransactionConfirmation.vue'
import TransactionResult from './AccountOverview/GddSend/TransactionResult.vue' import TransactionResult from './SendOverview/GddSend/TransactionResult.vue'
import { sendCoins } from '../../graphql/mutations.js' import { sendCoins } from '../../graphql/mutations.js'
const EMPTY_TRANSACTION_DATA = { const EMPTY_TRANSACTION_DATA = {
@ -50,7 +56,7 @@ const EMPTY_TRANSACTION_DATA = {
} }
export default { export default {
name: 'Overview', name: 'SendOverview',
components: { components: {
GddStatus, GddStatus,
GddSend, GddSend,

View File

@ -12,6 +12,7 @@ import SideBar from '@/components/SidebarPlugin'
import VueQrcode from 'vue-qrcode' import VueQrcode from 'vue-qrcode'
import VueMoment from 'vue-moment' import VueMoment from 'vue-moment'
import VueApexCharts from 'vue-apexcharts'
import clickOutside from '@/directives/click-ouside.js' import clickOutside from '@/directives/click-ouside.js'
import { focus } from 'vue-focus' import { focus } from 'vue-focus'
@ -44,6 +45,7 @@ global.localVue.use(RegeneratorRuntime)
global.localVue.use(SideBar) global.localVue.use(SideBar)
global.localVue.use(VueQrcode) global.localVue.use(VueQrcode)
global.localVue.use(VueMoment) global.localVue.use(VueMoment)
global.localVue.use(VueApexCharts)
global.localVue.component('validation-provider', ValidationProvider) global.localVue.component('validation-provider', ValidationProvider)
global.localVue.component('validation-observer', ValidationObserver) global.localVue.component('validation-observer', ValidationObserver)
global.localVue.directive('click-outside', clickOutside) global.localVue.directive('click-outside', clickOutside)

View File

@ -2615,6 +2615,18 @@ anymatch@^3.0.3, anymatch@~3.1.1:
normalize-path "^3.0.0" normalize-path "^3.0.0"
picomatch "^2.0.4" picomatch "^2.0.4"
apexcharts@^3.28.3:
version "3.28.3"
resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.28.3.tgz#22a6d9b234c82f6c2e1dd4aebba05b7603e2b1d2"
integrity sha512-EhghB2P27/Gjhwct8sSS0V63mdpRMx/ikH34dwUTqZQnkAEyOS/RKDmYjXBNA7zsAKBE/pThOdoTya6ADyk6zQ==
dependencies:
svg.draggable.js "^2.2.2"
svg.easing.js "^2.0.0"
svg.filter.js "^2.0.2"
svg.pathmorphing.js "^0.1.3"
svg.resize.js "^1.4.3"
svg.select.js "^3.0.1"
apollo-boost@^0.4.9: apollo-boost@^0.4.9:
version "0.4.9" version "0.4.9"
resolved "https://registry.yarnpkg.com/apollo-boost/-/apollo-boost-0.4.9.tgz#ab3ba539c2ca944e6fd156583a1b1954b17a6791" resolved "https://registry.yarnpkg.com/apollo-boost/-/apollo-boost-0.4.9.tgz#ab3ba539c2ca944e6fd156583a1b1954b17a6791"
@ -12600,6 +12612,61 @@ svg-tags@^1.0.0:
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
svg.draggable.js@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba"
integrity sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==
dependencies:
svg.js "^2.0.1"
svg.easing.js@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/svg.easing.js/-/svg.easing.js-2.0.0.tgz#8aa9946b0a8e27857a5c40a10eba4091e5691f12"
integrity sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=
dependencies:
svg.js ">=2.3.x"
svg.filter.js@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/svg.filter.js/-/svg.filter.js-2.0.2.tgz#91008e151389dd9230779fcbe6e2c9a362d1c203"
integrity sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=
dependencies:
svg.js "^2.2.5"
svg.js@>=2.3.x, svg.js@^2.0.1, svg.js@^2.2.5, svg.js@^2.4.0, svg.js@^2.6.5:
version "2.7.1"
resolved "https://registry.yarnpkg.com/svg.js/-/svg.js-2.7.1.tgz#eb977ed4737001eab859949b4a398ee1bb79948d"
integrity sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==
svg.pathmorphing.js@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz#c25718a1cc7c36e852ecabc380e758ac09bb2b65"
integrity sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==
dependencies:
svg.js "^2.4.0"
svg.resize.js@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/svg.resize.js/-/svg.resize.js-1.4.3.tgz#885abd248e0cd205b36b973c4b578b9a36f23332"
integrity sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==
dependencies:
svg.js "^2.6.5"
svg.select.js "^2.1.2"
svg.select.js@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-2.1.2.tgz#e41ce13b1acff43a7441f9f8be87a2319c87be73"
integrity sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==
dependencies:
svg.js "^2.2.5"
svg.select.js@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-3.0.1.tgz#a4198e359f3825739226415f82176a90ea5cc917"
integrity sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==
dependencies:
svg.js "^2.6.5"
svgo@^1.0.0: svgo@^1.0.0:
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167"
@ -13374,6 +13441,11 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
vue-apexcharts@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/vue-apexcharts/-/vue-apexcharts-1.6.2.tgz#0547826067f97e8ea67ca9423e524eb6669746ad"
integrity sha512-9HS3scJwWgKjmkcWIf+ndNDR0WytUJD8Ju0V2ZYcjYtlTLwJAf2SKUlBZaQTkDmwje/zMgulvZRi+MXmi+WkKw==
vue-apollo@^3.0.7: vue-apollo@^3.0.7:
version "3.0.7" version "3.0.7"
resolved "https://registry.yarnpkg.com/vue-apollo/-/vue-apollo-3.0.7.tgz#97a031d45641faa4888a6d5a7f71c40834359704" resolved "https://registry.yarnpkg.com/vue-apollo/-/vue-apollo-3.0.7.tgz#97a031d45641faa4888a6d5a7f71c40834359704"