mirror of
https://github.com/IT4Change/gradido.git
synced 2026-01-20 20:01:31 +00:00
Merge branch 'master' into community_update_old_frontend
This commit is contained in:
commit
9ec0cc947d
@ -1,20 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app" class="font-sans text-gray-800">
|
<div id="app" class="font-sans text-gray-800">
|
||||||
<header>
|
|
||||||
<b-col class="text-center">
|
|
||||||
<b-dropdown
|
|
||||||
size="sm"
|
|
||||||
split
|
|
||||||
variant="secondary"
|
|
||||||
:text="$t('language') + ' - ' + $i18n.locale"
|
|
||||||
class="m-md-2"
|
|
||||||
>
|
|
||||||
<b-dropdown-divider></b-dropdown-divider>
|
|
||||||
<b-dropdown-item @click.prevent="setLocale('de')">Deutsch</b-dropdown-item>
|
|
||||||
<b-dropdown-item @click.prevent="setLocale('en')">English</b-dropdown-item>
|
|
||||||
</b-dropdown>
|
|
||||||
</b-col>
|
|
||||||
</header>
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<particles-bg type="custom" :config="config" :bg="true" />
|
<particles-bg type="custom" :config="config" :bg="true" />
|
||||||
<component :is="$route.meta.requiresAuth ? 'DashboardLayout' : 'AuthLayoutGDD'" />
|
<component :is="$route.meta.requiresAuth ? 'DashboardLayout' : 'AuthLayoutGDD'" />
|
||||||
@ -25,7 +10,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import { ParticlesBg } from 'particles-bg-vue'
|
import { ParticlesBg } from 'particles-bg-vue'
|
||||||
import icon from './icon.js'
|
import icon from './icon.js'
|
||||||
import { localeChanged } from 'vee-validate'
|
|
||||||
import DashboardLayout from '@/views/Layout/DashboardLayout_gdd.vue'
|
import DashboardLayout from '@/views/Layout/DashboardLayout_gdd.vue'
|
||||||
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
|
import AuthLayoutGDD from '@/views/Layout/AuthLayout_gdd.vue'
|
||||||
|
|
||||||
@ -54,13 +38,6 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
setLocale(locale) {
|
|
||||||
this.$i18n.locale = locale
|
|
||||||
this.$store.commit('language', this.$i18n.locale)
|
|
||||||
localeChanged(locale)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -51,14 +51,11 @@ const communityAPI = {
|
|||||||
}
|
}
|
||||||
return apiPost(CONFIG.COMMUNITY_API__URL + 'createCoins/', payload)
|
return apiPost(CONFIG.COMMUNITY_API__URL + 'createCoins/', payload)
|
||||||
}, */
|
}, */
|
||||||
send: async (sessionId, email, amount, memo, targetDate) => {
|
send: async (sessionId, data) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
session_id: sessionId,
|
session_id: sessionId,
|
||||||
email,
|
|
||||||
amount,
|
|
||||||
memo,
|
|
||||||
target_date: targetDate,
|
|
||||||
auto_sign: true,
|
auto_sign: true,
|
||||||
|
...data,
|
||||||
}
|
}
|
||||||
return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload)
|
return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload)
|
||||||
},
|
},
|
||||||
|
|||||||
22
frontend/src/components/LanguageSwitch.vue
Normal file
22
frontend/src/components/LanguageSwitch.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<div class="language-switch">
|
||||||
|
<b-dropdown size="sm" :text="$t('language') + ' - ' + $i18n.locale">
|
||||||
|
<b-dropdown-item @click.prevent="setLocale('de')">Deutsch</b-dropdown-item>
|
||||||
|
<b-dropdown-item @click.prevent="setLocale('en')">English</b-dropdown-item>
|
||||||
|
</b-dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { localeChanged } from 'vee-validate'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'language-switch',
|
||||||
|
methods: {
|
||||||
|
setLocale(locale) {
|
||||||
|
this.$i18n.locale = locale
|
||||||
|
this.$store.commit('language', this.$i18n.locale)
|
||||||
|
localeChanged(locale)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
123
frontend/src/components/SidebarPlugin/SideBar.spec.js
Normal file
123
frontend/src/components/SidebarPlugin/SideBar.spec.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||||
|
import SideBar from './SideBar'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
describe('SideBar', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const stubs = {
|
||||||
|
RouterLink: RouterLinkStub,
|
||||||
|
}
|
||||||
|
|
||||||
|
const propsData = {
|
||||||
|
balance: 1234.56,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
email: 'test@example.org',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
$i18n: {
|
||||||
|
locale: 'en',
|
||||||
|
},
|
||||||
|
$t: jest.fn((t) => t),
|
||||||
|
$n: jest.fn((n) => n),
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(SideBar, { localVue, mocks, stubs, propsData })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component', () => {
|
||||||
|
expect(wrapper.find('#sidenav-main').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('balance', () => {
|
||||||
|
it('shows em-dash as balance while loading', () => {
|
||||||
|
expect(wrapper.find('div.row.text-center').text()).toBe('— GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows the when loaded', async () => {
|
||||||
|
wrapper.setProps({
|
||||||
|
pending: false,
|
||||||
|
})
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.find('div.row.text-center').text()).toBe('1234.56 GDD')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('navbar button', () => {
|
||||||
|
it('has a navbar button', () => {
|
||||||
|
expect(wrapper.find('button.navbar-toggler').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls showSidebar when clicked', async () => {
|
||||||
|
const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar')
|
||||||
|
wrapper.find('button.navbar-toggler').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(spy).toHaveBeenCalledWith(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('close siedbar', () => {
|
||||||
|
it('calls closeSidebar when clicked', async () => {
|
||||||
|
const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar')
|
||||||
|
wrapper.find('#sidenav-collapse-main').find('button.navbar-toggler').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(spy).toHaveBeenCalledWith(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('static menu items', () => {
|
||||||
|
describe("member's area", () => {
|
||||||
|
it('has a link to the elopage', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).text()).toBe('members_area')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('links to the elopage', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe(
|
||||||
|
'https://elopage.com/s/gradido/sign_in?locale=en',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with locale="de"', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks.$i18n.locale = 'de'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('links to the German elopage when locale is set to de', () => {
|
||||||
|
expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe(
|
||||||
|
'https://elopage.com/s/gradido/sign_in?locale=de',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('logout', () => {
|
||||||
|
it('has a logout button', () => {
|
||||||
|
expect(wrapper.findAll('li').at(1).text()).toBe('logout')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits logout when logout is clicked', async () => {
|
||||||
|
wrapper.findAll('li').at(1).find('a').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.emitted('logout')).toEqual([[]])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('language-switch', () => {
|
||||||
|
it('has a language-switch button', () => {
|
||||||
|
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<img :src="logo" class="navbar-brand-img" alt="..." />
|
<img :src="logo" class="navbar-brand-img" alt="..." />
|
||||||
</div>
|
</div>
|
||||||
<b-row class="text-center">
|
<b-row class="text-center">
|
||||||
<b-col>{{ $n(balance) }} GDD</b-col>
|
<b-col>{{ pending ? '—' : $n(balance) }} GDD</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
<slot name="mobile-right">
|
<slot name="mobile-right">
|
||||||
<ul class="nav align-items-center d-md-none">
|
<ul class="nav align-items-center d-md-none">
|
||||||
@ -32,9 +32,7 @@
|
|||||||
<div class="navbar-collapse-header d-md-none">
|
<div class="navbar-collapse-header d-md-none">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 collapse-brand">
|
<div class="col-6 collapse-brand">
|
||||||
<router-link to="/overview">
|
<img :src="logo" />
|
||||||
<img :src="logo" />
|
|
||||||
</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 collapse-close">
|
<div class="col-6 collapse-close">
|
||||||
<navbar-toggle-button @click.native="closeSidebar"></navbar-toggle-button>
|
<navbar-toggle-button @click.native="closeSidebar"></navbar-toggle-button>
|
||||||
@ -44,26 +42,29 @@
|
|||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<slot name="links"></slot>
|
<slot name="links"></slot>
|
||||||
</ul>
|
</ul>
|
||||||
<hr class="my-3" />
|
<hr class="my-2" />
|
||||||
<ul class="navbar-nav mb-md-3">
|
<ul class="navbar-nav ml-3">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a
|
<a
|
||||||
:href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
|
:href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
|
||||||
class="nav-link text-lg"
|
class="nav-link"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{{ $t('members_area') }}
|
{{ $t('members_area') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr class="my-3" />
|
|
||||||
<ul class="navbar-nav mb-md-3">
|
<ul class="navbar-nav ml-3">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link text-lg pointer" @click="logout">
|
<a class="nav-link pointer" @click="logout">
|
||||||
{{ $t('logout') }}
|
{{ $t('logout') }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="mt-5 ml-4">
|
||||||
|
<language-switch />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -71,12 +72,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import NavbarToggleButton from '@/components/NavbarToggleButton'
|
import NavbarToggleButton from '@/components/NavbarToggleButton'
|
||||||
import VueQrcode from 'vue-qrcode'
|
import VueQrcode from 'vue-qrcode'
|
||||||
|
import LanguageSwitch from '@/components/LanguageSwitch.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'sidebar',
|
name: 'sidebar',
|
||||||
components: {
|
components: {
|
||||||
NavbarToggleButton,
|
NavbarToggleButton,
|
||||||
VueQrcode,
|
VueQrcode,
|
||||||
|
LanguageSwitch,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
logo: {
|
logo: {
|
||||||
@ -93,6 +96,10 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
pending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -57,7 +57,6 @@
|
|||||||
},
|
},
|
||||||
"transaction":{
|
"transaction":{
|
||||||
"show_all":"View all <strong>{count}</strong> transactions.",
|
"show_all":"View all <strong>{count}</strong> transactions.",
|
||||||
"show_part": "The last <strong>{count}</strong> transactions.",
|
|
||||||
"nullTransactions":"You don't have any transactions on your account yet.",
|
"nullTransactions":"You don't have any transactions on your account yet.",
|
||||||
"more": "more"
|
"more": "more"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="main-content">
|
<div class="main-content mt-4">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
|
<language-switch class="text-center mb-5 mt-5" />
|
||||||
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
|
<content-footer v-if="!$route.meta.hideFooter"></content-footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import ContentFooter from './ContentFooter.vue'
|
import ContentFooter from './ContentFooter.vue'
|
||||||
|
import LanguageSwitch from '@/components/LanguageSwitch.vue'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ContentFooter,
|
ContentFooter,
|
||||||
|
LanguageSwitch,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -59,10 +59,6 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
expect(wrapper.find('nav#sidenav-main').exists()).toBeTruthy()
|
expect(wrapper.find('nav#sidenav-main').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has a notifications component', () => {
|
|
||||||
expect(wrapper.find('div.notifications').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a main content div', () => {
|
it('has a main content div', () => {
|
||||||
expect(wrapper.find('div.main-content').exists()).toBeTruthy()
|
expect(wrapper.find('div.main-content').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
@ -79,31 +75,35 @@ describe('DashboardLayoutGdd', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('has five items in the navbar', () => {
|
it('has five items in the navbar', () => {
|
||||||
expect(navbar.findAll('ul > li')).toHaveLength(2)
|
expect(navbar.findAll('ul > a')).toHaveLength(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has first item "send" in navbar', () => {
|
it('has first item "send" in navbar', () => {
|
||||||
expect(navbar.findAll('ul > li').at(0).text()).toEqual('send')
|
expect(navbar.findAll('ul > a').at(0).text()).toEqual('send')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has first item "send" linked to overview in navbar', () => {
|
it('has first item "send" linked to overview in navbar', () => {
|
||||||
navbar.findAll('ul > li').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().to).toBe('/overview')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has second item "transactions" in navbar', () => {
|
it('has second item "transactions" in navbar', () => {
|
||||||
expect(navbar.findAll('ul > li').at(1).text()).toEqual('transactions')
|
expect(navbar.findAll('ul > a').at(1).text()).toEqual('transactions')
|
||||||
})
|
})
|
||||||
|
|
||||||
// to do: get this working!
|
// to do: get this working!
|
||||||
it.skip('has second item "transactions" linked to transactions in navbar', async () => {
|
it.skip('has second item "transactions" linked to transactions in navbar', async () => {
|
||||||
navbar.findAll('ul > li > a').at(1).trigger('click')
|
navbar.findAll('ul > a').at(1).trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
await jest.runAllTimers()
|
await jest.runAllTimers()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/transactions')
|
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/transactions')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// it('has tree items in the navbar', () => {
|
||||||
|
// expect(navbar.findAll('ul > li')).toHaveLength(3)
|
||||||
|
// })
|
||||||
|
//
|
||||||
// it('has third item "My profile" in navbar', () => {
|
// it('has third item "My profile" in navbar', () => {
|
||||||
// expect(navbar.findAll('ul > li').at(2).text()).toEqual('site.navbar.my-profil')
|
// expect(navbar.findAll('ul > li').at(2).text()).toEqual('site.navbar.my-profil')
|
||||||
// })
|
// })
|
||||||
|
|||||||
@ -1,30 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<notifications></notifications>
|
<side-bar @logout="logout" :balance="balance" :pending="pending">
|
||||||
<side-bar @logout="logout" :balance="balance">
|
|
||||||
<template slot="links">
|
<template slot="links">
|
||||||
<b-nav-item href="#!" to="/overview">
|
<sidebar-item
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('send') }}</b-nav-text>
|
:link="{
|
||||||
</b-nav-item>
|
name: $t('send'),
|
||||||
<b-nav-item href="#!" to="/transactions">
|
path: '/overview',
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('transactions') }}</b-nav-text>
|
}"
|
||||||
</b-nav-item>
|
></sidebar-item>
|
||||||
|
<sidebar-item
|
||||||
|
:link="{
|
||||||
|
name: $t('transactions'),
|
||||||
|
path: '/transactions',
|
||||||
|
}"
|
||||||
|
></sidebar-item>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<b-nav-item href="#!" to="/profile">
|
<b-nav-item href="#!" to="/profile">
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
|
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.my-profil') }}</b-nav-text>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
<b-nav-item href="#!" to="/profileedit">
|
<b-nav-item href="#!" to="/profileedit">
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
|
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.settings') }}</b-nav-text>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
<b-nav-item href="#!" to="/activity">
|
<b-nav-item href="#!" to="/activity">
|
||||||
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
|
<b-nav-text class="p-0 text-lg text-muted">{{ $t('site.navbar.activity') }}</b-nav-text>
|
||||||
</b-nav-item>
|
</b-nav-item>
|
||||||
-->
|
-->
|
||||||
</template>
|
</template>
|
||||||
</side-bar>
|
</side-bar>
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<dashboard-navbar :type="$route.meta.navbarType"></dashboard-navbar>
|
<dashboard-navbar :type="$route.meta.navbarType"></dashboard-navbar>
|
||||||
|
|
||||||
<div @click="$sidebar.displaySidebar(false)">
|
<div @click="$sidebar.displaySidebar(false)">
|
||||||
<fade-transition :duration="200" origin="center top" mode="out-in">
|
<fade-transition :duration="200" origin="center top" mode="out-in">
|
||||||
<!-- your content here -->
|
<!-- your content here -->
|
||||||
@ -33,6 +38,7 @@
|
|||||||
:gdt-balance="GdtBalance"
|
:gdt-balance="GdtBalance"
|
||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:transactionCount="transactionCount"
|
:transactionCount="transactionCount"
|
||||||
|
:pending="pending"
|
||||||
@update-balance="updateBalance"
|
@update-balance="updateBalance"
|
||||||
@update-transactions="updateTransactions"
|
@update-transactions="updateTransactions"
|
||||||
></router-view>
|
></router-view>
|
||||||
@ -83,6 +89,7 @@ export default {
|
|||||||
transactions: [],
|
transactions: [],
|
||||||
bookedBalance: 0,
|
bookedBalance: 0,
|
||||||
transactionCount: 0,
|
transactionCount: 0,
|
||||||
|
pending: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -99,6 +106,7 @@ export default {
|
|||||||
this.$router.push('/login')
|
this.$router.push('/login')
|
||||||
},
|
},
|
||||||
async updateTransactions() {
|
async updateTransactions() {
|
||||||
|
this.pending = true
|
||||||
const result = await communityAPI.transactions(this.$store.state.sessionId)
|
const result = await communityAPI.transactions(this.$store.state.sessionId)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.GdtBalance = Number(result.result.data.gdtSum)
|
this.GdtBalance = Number(result.result.data.gdtSum)
|
||||||
@ -106,7 +114,9 @@ export default {
|
|||||||
this.balance = Number(result.result.data.decay)
|
this.balance = Number(result.result.data.decay)
|
||||||
this.bookedBalance = Number(result.result.data.balance)
|
this.bookedBalance = Number(result.result.data.balance)
|
||||||
this.transactionCount = result.result.data.count
|
this.transactionCount = result.result.data.count
|
||||||
|
this.pending = false
|
||||||
} else {
|
} else {
|
||||||
|
this.pending = true
|
||||||
// what to do when loading balance fails?
|
// what to do when loading balance fails?
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<li class="nav-item d-sm-none"></li>
|
<li class="nav-item d-sm-none"></li>
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
<b-navbar-nav class="align-items-center ml-auto ml-md-0">
|
<b-navbar-nav class="align-items-center ml-auto ml-md-0">
|
||||||
<a class="pr-1 nav-link" slot="title-container pointer">
|
<div class="pr-1" slot="title-container ">
|
||||||
<b-media no-body class="align-items-center">
|
<b-media no-body class="align-items-center">
|
||||||
<span class="pb-2 text-lg font-weight-bold">
|
<span class="pb-2 text-lg font-weight-bold">
|
||||||
{{ $store.state.email }}
|
{{ $store.state.email }}
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</b-media-body>
|
</b-media-body>
|
||||||
</b-media>
|
</b-media>
|
||||||
</a>
|
</div>
|
||||||
</b-navbar-nav>
|
</b-navbar-nav>
|
||||||
</base-nav>
|
</base-nav>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -34,30 +34,5 @@ describe('AccountOverview', () => {
|
|||||||
it('has a transactions table', () => {
|
it('has a transactions table', () => {
|
||||||
expect(wrapper.find('gdd-table-stub').exists()).toBeTruthy()
|
expect(wrapper.find('gdd-table-stub').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('updateBalance method', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
wrapper.find('gdd-send-stub').vm.$emit('update-balance', {
|
|
||||||
ammount: 42,
|
|
||||||
})
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('emmits updateBalance with correct value', () => {
|
|
||||||
expect(wrapper.emitted('update-balance')).toEqual([[42]])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('toggleShowList method', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
wrapper.setProps({ showTransactionList: false })
|
|
||||||
wrapper.find('gdd-send-stub').vm.$emit('toggle-show-list', true)
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('changes the value of property showTransactionList', () => {
|
|
||||||
expect(wrapper.vm.showTransactionList).toBeTruthy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,25 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<base-header class="pb-4 pt-2 bg-transparent"></base-header>
|
<base-header class="pb-lg-4 pt-lg-2 bg-transparent"></base-header>
|
||||||
<b-container fluid class="p-2 mt-5">
|
<b-container fluid class="p-lg-2 mt-lg-5">
|
||||||
<gdd-status v-if="showTransactionList" :balance="balance" :gdt-balance="GdtBalance" />
|
<gdd-status
|
||||||
<br />
|
v-if="showContext"
|
||||||
<gdd-send
|
:pending="pending"
|
||||||
:balance="balance"
|
:balance="balance"
|
||||||
:show-transaction-list="showTransactionList"
|
:gdt-balance="GdtBalance"
|
||||||
@update-balance="updateBalance"
|
|
||||||
@toggle-show-list="toggleShowList"
|
|
||||||
/>
|
/>
|
||||||
|
<br />
|
||||||
|
<gdd-send :currentTransactionStep="currentTransactionStep">
|
||||||
|
<template #transaction-form>
|
||||||
|
<transaction-form :balance="balance" @set-transaction="setTransaction"></transaction-form>
|
||||||
|
</template>
|
||||||
|
<template #transaction-confirmation>
|
||||||
|
<transaction-confirmation
|
||||||
|
:email="transactionData.email"
|
||||||
|
:amount="transactionData.amount"
|
||||||
|
:memo="transactionData.memo"
|
||||||
|
:date="transactionData.target_date"
|
||||||
|
@send-transaction="sendTransaction"
|
||||||
|
@on-reset="onReset"
|
||||||
|
></transaction-confirmation>
|
||||||
|
</template>
|
||||||
|
<template #transaction-result>
|
||||||
|
<transaction-result :error="error" @on-reset="onReset"></transaction-result>
|
||||||
|
</template>
|
||||||
|
</gdd-send>
|
||||||
<hr />
|
<hr />
|
||||||
<gdd-table
|
<gdd-table
|
||||||
v-if="showTransactionList"
|
v-if="showContext"
|
||||||
:transactions="transactions"
|
:transactions="transactions"
|
||||||
:max="5"
|
:max="5"
|
||||||
:timestamp="timestamp"
|
:timestamp="timestamp"
|
||||||
:transactionCount="transactionCount"
|
:transactionCount="transactionCount"
|
||||||
@update-transactions="updateTransactions"
|
@update-transactions="$emit('update-transactions')"
|
||||||
/>
|
/>
|
||||||
<gdd-table-footer :count="transactionCount" />
|
<gdd-table-footer v-if="showContext" :count="transactionCount" />
|
||||||
</b-container>
|
</b-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -28,6 +45,17 @@ import GddStatus from './AccountOverview/GddStatus.vue'
|
|||||||
import GddSend from './AccountOverview/GddSend.vue'
|
import GddSend from './AccountOverview/GddSend.vue'
|
||||||
import GddTable from './AccountOverview/GddTable.vue'
|
import GddTable from './AccountOverview/GddTable.vue'
|
||||||
import GddTableFooter from './AccountOverview/GddTableFooter.vue'
|
import GddTableFooter from './AccountOverview/GddTableFooter.vue'
|
||||||
|
import TransactionForm from './AccountOverview/GddSend/TransactionForm.vue'
|
||||||
|
import TransactionConfirmation from './AccountOverview/GddSend/TransactionConfirmation.vue'
|
||||||
|
import TransactionResult from './AccountOverview/GddSend/TransactionResult.vue'
|
||||||
|
import communityAPI from '../../apis/communityAPI.js'
|
||||||
|
|
||||||
|
const EMPTY_TRANSACTION_DATA = {
|
||||||
|
email: '',
|
||||||
|
amount: 0,
|
||||||
|
memo: '',
|
||||||
|
target_date: '',
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Overview',
|
name: 'Overview',
|
||||||
@ -36,11 +64,16 @@ export default {
|
|||||||
GddSend,
|
GddSend,
|
||||||
GddTable,
|
GddTable,
|
||||||
GddTableFooter,
|
GddTableFooter,
|
||||||
|
TransactionForm,
|
||||||
|
TransactionConfirmation,
|
||||||
|
TransactionResult,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showTransactionList: true,
|
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
|
transactionData: EMPTY_TRANSACTION_DATA,
|
||||||
|
error: false,
|
||||||
|
currentTransactionStep: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@ -50,16 +83,35 @@ export default {
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
transactionCount: { type: Number, default: 0 },
|
transactionCount: { type: Number, default: 0 },
|
||||||
|
pending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showContext() {
|
||||||
|
return this.currentTransactionStep === 0
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleShowList(bool) {
|
setTransaction(data) {
|
||||||
this.showTransactionList = bool
|
data.target_date = new Date(Date.now()).toISOString()
|
||||||
|
this.transactionData = { ...data }
|
||||||
|
this.currentTransactionStep = 1
|
||||||
},
|
},
|
||||||
updateBalance(data) {
|
async sendTransaction() {
|
||||||
this.$emit('update-balance', data.ammount)
|
const result = await communityAPI.send(this.$store.state.sessionId, this.transactionData)
|
||||||
|
if (result.success) {
|
||||||
|
this.error = false
|
||||||
|
this.$emit('update-balance', this.transactionData.amount)
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
}
|
||||||
|
this.currentTransactionStep = 2
|
||||||
},
|
},
|
||||||
updateTransactions() {
|
onReset() {
|
||||||
this.$emit('update-transactions')
|
this.transactionData = EMPTY_TRANSACTION_DATA
|
||||||
|
this.currentTransactionStep = 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,18 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import GddSend from './GddSend'
|
import GddSend from './GddSend'
|
||||||
import Vuex from 'vuex'
|
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
describe('GddSend', () => {
|
describe('GddSend', () => {
|
||||||
let wrapper
|
let wrapper
|
||||||
|
|
||||||
const state = {
|
|
||||||
user: {
|
|
||||||
balance: 1234,
|
|
||||||
balance_gdt: 9876,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
state,
|
|
||||||
})
|
|
||||||
|
|
||||||
const mocks = {
|
const mocks = {
|
||||||
// $n: jest.fn((n) => n),
|
|
||||||
$t: jest.fn((t) => t),
|
$t: jest.fn((t) => t),
|
||||||
$moment: jest.fn((m) => ({
|
$store: {
|
||||||
format: () => m,
|
state: {
|
||||||
})),
|
sessionId: 1234,
|
||||||
|
},
|
||||||
|
},
|
||||||
$i18n: {
|
$i18n: {
|
||||||
locale: jest.fn(() => 'en'),
|
locale: jest.fn(() => 'en'),
|
||||||
},
|
},
|
||||||
@ -31,7 +20,7 @@ describe('GddSend', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(GddSend, { localVue, store, mocks })
|
return mount(GddSend, { localVue, mocks })
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
@ -42,88 +31,5 @@ describe('GddSend', () => {
|
|||||||
it('renders the component', () => {
|
it('renders the component', () => {
|
||||||
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
|
expect(wrapper.find('div.gdd-send').exists()).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('warning messages', () => {
|
|
||||||
it('has a warning message', () => {
|
|
||||||
expect(wrapper.find('div.alert-default').find('span').text()).toBe('form.attention')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('transaction form', () => {
|
|
||||||
describe('email field', () => {
|
|
||||||
it('has an input field of type email', () => {
|
|
||||||
expect(wrapper.find('#input-group-1').find('input').attributes('type')).toBe('email')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has an envelope icon', () => {
|
|
||||||
expect(wrapper.find('#input-group-1').find('svg').attributes('aria-label')).toBe(
|
|
||||||
'envelope',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a label form.receiver', () => {
|
|
||||||
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a placeholder "E-Mail"', () => {
|
|
||||||
expect(wrapper.find('#input-group-1').find('input').attributes('placeholder')).toBe(
|
|
||||||
'E-Mail',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('ammount field', () => {
|
|
||||||
it('has an input field of type number', () => {
|
|
||||||
expect(wrapper.find('#input-group-2').find('input').attributes('type')).toBe('number')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has an GDD text icon', () => {
|
|
||||||
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a label form.amount', () => {
|
|
||||||
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a placeholder "0.01"', () => {
|
|
||||||
expect(wrapper.find('#input-group-2').find('input').attributes('placeholder')).toBe(
|
|
||||||
'0.01',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('message text box', () => {
|
|
||||||
it('has an textarea field', () => {
|
|
||||||
expect(wrapper.find('#input-group-3').find('textarea').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has an chat-right-text icon', () => {
|
|
||||||
expect(wrapper.find('#input-group-3').find('svg').attributes('aria-label')).toBe(
|
|
||||||
'chat right text',
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has a label form.memo', () => {
|
|
||||||
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('cancel button', () => {
|
|
||||||
it('has a cancel button', () => {
|
|
||||||
expect(wrapper.find('button[type="reset"]').exists()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has the text "form.cancel"', () => {
|
|
||||||
expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset')
|
|
||||||
})
|
|
||||||
|
|
||||||
it.skip('clears the email field on click', async () => {
|
|
||||||
wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv')
|
|
||||||
wrapper.find('button[type="reset"]').trigger('click')
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
expect(wrapper.vm.form.email).toBeNull()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,346 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="gdd-send">
|
<div class="gdd-send">
|
||||||
<b-row v-show="showTransactionList">
|
<slot :name="transactionSteps[currentTransactionStep]" />
|
||||||
<b-col xl="12" md="12">
|
|
||||||
<b-alert show dismissible variant="default" class="text-center">
|
|
||||||
<span class="alert-text h3 text-light" v-html="$t('form.attention')"></span>
|
|
||||||
</b-alert>
|
|
||||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
|
||||||
<!--
|
|
||||||
<b-alert show variant="secondary">
|
|
||||||
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
|
||||||
<b-col v-show="!scan" lg="12" class="text-right">
|
|
||||||
<a @click="toggle" class="nav-link pointer">
|
|
||||||
<img src="img/icons/gradido/qr-scan-pure.png" height="50" />
|
|
||||||
</a>
|
|
||||||
</b-col>
|
|
||||||
|
|
||||||
<div v-if="scan">
|
|
||||||
<b-row>
|
|
||||||
<qrcode-capture @detect="onDetect" capture="user" ></qrcode-capture>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<qrcode-stream class="mt-3" @decode="onDecode" @detect="onDetect"></qrcode-stream>
|
|
||||||
|
|
||||||
<b-container>
|
|
||||||
<b-row>
|
|
||||||
<b-col lg="8">
|
|
||||||
<b-alert show variant="secondary">
|
|
||||||
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
|
||||||
</b-alert>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-container>
|
|
||||||
</div>
|
|
||||||
<div @click="toggle">
|
|
||||||
<b-alert v-show="scan" show variant="primary" class="pointer text-center">
|
|
||||||
<span class="alert-text">
|
|
||||||
<strong>{{ $t('form.cancel') }}</strong>
|
|
||||||
</span>
|
|
||||||
</b-alert>
|
|
||||||
</div>
|
|
||||||
</b-alert>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
|
|
||||||
<b-form
|
|
||||||
role="form"
|
|
||||||
@submit.prevent="handleSubmit(onSubmit)"
|
|
||||||
@reset="onReset"
|
|
||||||
v-if="show"
|
|
||||||
>
|
|
||||||
<!-- <div>
|
|
||||||
<qrcode-drop-zone id="input-0" v-model="form.img"></qrcode-drop-zone>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
-->
|
|
||||||
<div>
|
|
||||||
<validation-provider
|
|
||||||
name="Email"
|
|
||||||
:rules="{
|
|
||||||
required: true,
|
|
||||||
email: true,
|
|
||||||
is_not: $store.state.email,
|
|
||||||
}"
|
|
||||||
v-slot="{ errors }"
|
|
||||||
>
|
|
||||||
<b-row>
|
|
||||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
|
|
||||||
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
|
||||||
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-input-group
|
|
||||||
id="input-group-1"
|
|
||||||
label="Empfänger:"
|
|
||||||
label-for="input-1"
|
|
||||||
description="We'll never share your email with anyone else."
|
|
||||||
size="lg"
|
|
||||||
class="mb-3"
|
|
||||||
>
|
|
||||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
|
||||||
<b-icon icon="envelope" class="display-3"></b-icon>
|
|
||||||
</b-input-group-prepend>
|
|
||||||
<b-form-input
|
|
||||||
id="input-1"
|
|
||||||
v-model="form.email"
|
|
||||||
type="email"
|
|
||||||
placeholder="E-Mail"
|
|
||||||
style="font-size: xx-large; padding-left: 20px"
|
|
||||||
></b-form-input>
|
|
||||||
</b-input-group>
|
|
||||||
</validation-provider>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<div>
|
|
||||||
<validation-provider
|
|
||||||
:name="$t('form.amount')"
|
|
||||||
:rules="{
|
|
||||||
required: true,
|
|
||||||
double: [2, $i18n.locale === 'de' ? ',' : '.'],
|
|
||||||
between: [0.01, balance],
|
|
||||||
}"
|
|
||||||
v-slot="{ errors }"
|
|
||||||
>
|
|
||||||
<b-row>
|
|
||||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
|
|
||||||
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
|
||||||
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-input-group
|
|
||||||
id="input-group-2"
|
|
||||||
label="Betrag:"
|
|
||||||
label-for="input-2"
|
|
||||||
size="lg"
|
|
||||||
class="mb-3"
|
|
||||||
>
|
|
||||||
<b-input-group-prepend class="p-2 d-none d-md-block">
|
|
||||||
<div class="h3 pt-3 pr-3">GDD</div>
|
|
||||||
</b-input-group-prepend>
|
|
||||||
<b-form-input
|
|
||||||
id="input-2"
|
|
||||||
v-model="form.amount"
|
|
||||||
type="number"
|
|
||||||
:lang="$i18n.locale"
|
|
||||||
:placeholder="$n(0.01)"
|
|
||||||
step="0.01"
|
|
||||||
style="font-size: xx-large; padding-left: 20px"
|
|
||||||
></b-form-input>
|
|
||||||
</b-input-group>
|
|
||||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
|
|
||||||
<b-input-group id="input-group-3">
|
|
||||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
|
||||||
<b-icon icon="chat-right-text" class="display-3"></b-icon>
|
|
||||||
</b-input-group-prepend>
|
|
||||||
<b-form-textarea
|
|
||||||
rows="3"
|
|
||||||
v-model="form.memo"
|
|
||||||
class="pl-3"
|
|
||||||
style="font-size: x-large"
|
|
||||||
></b-form-textarea>
|
|
||||||
</b-input-group>
|
|
||||||
</validation-provider>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<b-button type="reset" variant="secondary" @click="onReset">
|
|
||||||
{{ $t('form.reset') }}
|
|
||||||
</b-button>
|
|
||||||
</b-col>
|
|
||||||
<b-col class="text-right">
|
|
||||||
<b-button type="submit" variant="success">
|
|
||||||
{{ $t('form.send_now') }}
|
|
||||||
</b-button>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
</b-form>
|
|
||||||
</validation-observer>
|
|
||||||
</b-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row v-show="row_check">
|
|
||||||
<b-col>
|
|
||||||
<div class="display-4 p-4">{{ $t('form.send_check') }}</div>
|
|
||||||
|
|
||||||
<b-list-group>
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ ajaxCreateData.email }}
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ ajaxCreateData.amount }} GDD
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.amount') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ ajaxCreateData.memo ? ajaxCreateData.memo : '-' }}
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.message') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
|
||||||
{{ $moment(ajaxCreateData.target_date).format('DD.MM.YYYY - HH:mm:ss') }}
|
|
||||||
<b-badge variant="primary" pill>{{ $t('form.date') }}</b-badge>
|
|
||||||
</b-list-group-item>
|
|
||||||
</b-list-group>
|
|
||||||
<hr />
|
|
||||||
<b-row>
|
|
||||||
<b-col>
|
|
||||||
<b-button @click="onReset">{{ $t('form.cancel') }}</b-button>
|
|
||||||
</b-col>
|
|
||||||
<b-col class="text-right">
|
|
||||||
<b-button variant="success" @click="sendTransaction">
|
|
||||||
{{ $t('form.send_now') }}
|
|
||||||
</b-button>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row v-show="row_thx">
|
|
||||||
<b-col>
|
|
||||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
|
||||||
<div class="display-2 p-4">
|
|
||||||
{{ $t('form.thx') }}
|
|
||||||
<hr />
|
|
||||||
{{ $t('form.send_transaction_success') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="text-center">
|
|
||||||
<b-button variant="success" @click="onReset">{{ $t('form.close') }}</b-button>
|
|
||||||
</p>
|
|
||||||
</b-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
<b-row v-show="row_error">
|
|
||||||
<b-col>
|
|
||||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
|
||||||
<div class="display-2 p-4">
|
|
||||||
{{ $t('form.sorry') }}
|
|
||||||
<hr />
|
|
||||||
{{ $t('form.send_transaction_error') }}
|
|
||||||
</div>
|
|
||||||
<p class="text-center">
|
|
||||||
<b-button variant="success" @click="onReset">{{ $t('form.close') }}</b-button>
|
|
||||||
</p>
|
|
||||||
</b-card>
|
|
||||||
</b-col>
|
|
||||||
</b-row>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'
|
|
||||||
import { BIcon } from 'bootstrap-vue'
|
|
||||||
import communityAPI from '../../../apis/communityAPI.js'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'GddSent',
|
name: 'GddSend',
|
||||||
components: {
|
|
||||||
// QrcodeStream,
|
|
||||||
// QrcodeDropZone,
|
|
||||||
BIcon,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
balance: { type: Number, default: 0 },
|
|
||||||
showTransactionList: { type: Boolean, default: true },
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// scan: false,
|
transactionSteps: ['transaction-form', 'transaction-confirmation', 'transaction-result'],
|
||||||
show: true,
|
|
||||||
form: {
|
|
||||||
img: '',
|
|
||||||
email: '',
|
|
||||||
amount: '',
|
|
||||||
memo: '',
|
|
||||||
},
|
|
||||||
ajaxCreateData: {
|
|
||||||
email: '',
|
|
||||||
amount: 0,
|
|
||||||
target_date: '',
|
|
||||||
memo: '',
|
|
||||||
auto_sign: true,
|
|
||||||
},
|
|
||||||
send: false,
|
|
||||||
row_check: false,
|
|
||||||
row_thx: false,
|
|
||||||
row_error: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
props: {
|
||||||
methods: {
|
currentTransactionStep: { type: Number, default: 0 },
|
||||||
// toggle() {
|
|
||||||
// this.scan = !this.scan
|
|
||||||
// },
|
|
||||||
// async onDecode(decodedString) {
|
|
||||||
// const arr = JSON.parse(decodedString)
|
|
||||||
// this.form.email = arr[0].email
|
|
||||||
// this.form.amount = arr[0].amount
|
|
||||||
// this.scan = false
|
|
||||||
// },
|
|
||||||
async onSubmit() {
|
|
||||||
// event.preventDefault()
|
|
||||||
this.ajaxCreateData.email = this.form.email
|
|
||||||
this.ajaxCreateData.amount = this.form.amount
|
|
||||||
const now = new Date(Date.now()).toISOString()
|
|
||||||
this.ajaxCreateData.target_date = now
|
|
||||||
this.ajaxCreateData.memo = this.form.memo
|
|
||||||
this.$emit('toggle-show-list', false)
|
|
||||||
this.row_check = true
|
|
||||||
this.row_thx = false
|
|
||||||
this.row_error = false
|
|
||||||
},
|
|
||||||
async sendTransaction() {
|
|
||||||
const result = await communityAPI.send(
|
|
||||||
this.$store.state.sessionId,
|
|
||||||
this.ajaxCreateData.email,
|
|
||||||
this.ajaxCreateData.amount,
|
|
||||||
this.ajaxCreateData.memo,
|
|
||||||
this.ajaxCreateData.target_date,
|
|
||||||
)
|
|
||||||
if (result.success) {
|
|
||||||
this.$emit('toggle-show-list', false)
|
|
||||||
this.row_check = false
|
|
||||||
this.row_thx = true
|
|
||||||
this.row_error = false
|
|
||||||
this.$emit('update-balance', { ammount: this.ajaxCreateData.amount })
|
|
||||||
} else {
|
|
||||||
this.$emit('toggle-show-list', true)
|
|
||||||
this.row_check = false
|
|
||||||
this.row_thx = false
|
|
||||||
this.row_error = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onReset(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.form.email = ''
|
|
||||||
this.form.amount = ''
|
|
||||||
this.form.memo = ''
|
|
||||||
this.show = false
|
|
||||||
this.$emit('toggle-show-list', true)
|
|
||||||
this.row_check = false
|
|
||||||
this.row_thx = false
|
|
||||||
this.row_error = false
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.show = true
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
.pointer {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
video {
|
|
||||||
max-height: 665px;
|
|
||||||
max-width: 665px;
|
|
||||||
}
|
|
||||||
span.errors {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
65
frontend/src/views/Pages/AccountOverview/GddSend/QrCode.vue
Normal file
65
frontend/src/views/Pages/AccountOverview/GddSend/QrCode.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<b-alert show variant="secondary">
|
||||||
|
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
||||||
|
<b-col v-show="!scan" lg="12" class="text-right">
|
||||||
|
<a @click="toggle" class="nav-link pointer">
|
||||||
|
<img src="img/icons/gradido/qr-scan-pure.png" height="50" />
|
||||||
|
</a>
|
||||||
|
</b-col>
|
||||||
|
|
||||||
|
<div v-if="scan">
|
||||||
|
<b-row>
|
||||||
|
<qrcode-capture @detect="onDetect" capture="user"></qrcode-capture>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
<qrcode-stream class="mt-3" @decode="onDecode" @detect="onDetect"></qrcode-stream>
|
||||||
|
|
||||||
|
<b-container>
|
||||||
|
<b-row>
|
||||||
|
<b-col lg="8">
|
||||||
|
<b-alert show variant="secondary">
|
||||||
|
<span class="alert-text" v-html="$t('form.scann_code')"></span>
|
||||||
|
</b-alert>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</b-container>
|
||||||
|
</div>
|
||||||
|
<div @click="toggle">
|
||||||
|
<b-alert v-show="scan" show variant="primary" class="pointer text-center">
|
||||||
|
<span class="alert-text">
|
||||||
|
<strong>{{ $t('form.cancel') }}</strong>
|
||||||
|
</span>
|
||||||
|
</b-alert>
|
||||||
|
</div>
|
||||||
|
</b-alert>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { QrcodeStream } from 'vue-qrcode-reader'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'QrCode',
|
||||||
|
components: {
|
||||||
|
QrcodeStream,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
scan: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
this.scan = !this.scan
|
||||||
|
},
|
||||||
|
async onDecode(decodedString) {
|
||||||
|
const arr = JSON.parse(decodedString)
|
||||||
|
this.$emit('set-transaction', { email: arr[0].email, amount: arr[0].amount })
|
||||||
|
this.scan = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<div class="display-4 p-4">{{ $t('form.send_check') }}</div>
|
||||||
|
<b-list-group>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ email }}
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ amount }} GDD
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.amount') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ memo ? memo : '-' }}
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.message') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
<b-list-group-item class="d-flex justify-content-between align-items-center">
|
||||||
|
{{ date }}
|
||||||
|
{{ $moment(date).format('DD.MM.YYYY - HH:mm:ss') }}
|
||||||
|
<b-badge variant="primary" pill>{{ $t('form.date') }}</b-badge>
|
||||||
|
</b-list-group-item>
|
||||||
|
</b-list-group>
|
||||||
|
<hr />
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<b-button @click="$emit('on-reset')">{{ $t('form.cancel') }}</b-button>
|
||||||
|
</b-col>
|
||||||
|
<b-col class="text-right">
|
||||||
|
<b-button variant="success" @click="$emit('send-transaction')">
|
||||||
|
{{ $t('form.send_now') }}
|
||||||
|
</b-button>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TransactionConfirmation',
|
||||||
|
props: {
|
||||||
|
email: { type: String, default: '' },
|
||||||
|
amount: { type: String, default: '' },
|
||||||
|
memo: { type: String, default: '' },
|
||||||
|
date: { type: String, default: '' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import TransactionForm from './TransactionForm'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
describe('GddSend', () => {
|
||||||
|
let wrapper
|
||||||
|
|
||||||
|
const mocks = {
|
||||||
|
$t: jest.fn((t) => t),
|
||||||
|
$moment: jest.fn((m) => ({
|
||||||
|
format: () => m,
|
||||||
|
})),
|
||||||
|
$i18n: {
|
||||||
|
locale: jest.fn(() => 'en'),
|
||||||
|
},
|
||||||
|
$n: jest.fn((n) => String(n)),
|
||||||
|
$store: {
|
||||||
|
state: {
|
||||||
|
email: 'user@example.org',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(TransactionForm, { localVue, mocks })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders the component', () => {
|
||||||
|
expect(wrapper.find('div.transaction-form').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('warning messages', () => {
|
||||||
|
it('has a warning message', () => {
|
||||||
|
expect(wrapper.find('div.alert-default').find('span').text()).toBe('form.attention')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('transaction form', () => {
|
||||||
|
describe('email field', () => {
|
||||||
|
it('has an input field of type email', () => {
|
||||||
|
expect(wrapper.find('#input-group-1').find('input').attributes('type')).toBe('email')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an envelope icon', () => {
|
||||||
|
expect(wrapper.find('#input-group-1').find('svg').attributes('aria-label')).toBe(
|
||||||
|
'envelope',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a label form.receiver', () => {
|
||||||
|
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a placeholder "E-Mail"', () => {
|
||||||
|
expect(wrapper.find('#input-group-1').find('input').attributes('placeholder')).toBe(
|
||||||
|
'E-Mail',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('ammount field', () => {
|
||||||
|
it('has an input field of type number', () => {
|
||||||
|
expect(wrapper.find('#input-group-2').find('input').attributes('type')).toBe('number')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an GDD text icon', () => {
|
||||||
|
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a label form.amount', () => {
|
||||||
|
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a placeholder "0.01"', () => {
|
||||||
|
expect(wrapper.find('#input-group-2').find('input').attributes('placeholder')).toBe(
|
||||||
|
'0.01',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('message text box', () => {
|
||||||
|
it('has an textarea field', () => {
|
||||||
|
expect(wrapper.find('#input-group-3').find('textarea').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has an chat-right-text icon', () => {
|
||||||
|
expect(wrapper.find('#input-group-3').find('svg').attributes('aria-label')).toBe(
|
||||||
|
'chat right text',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has a label form.memo', () => {
|
||||||
|
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('cancel button', () => {
|
||||||
|
it('has a cancel button', () => {
|
||||||
|
expect(wrapper.find('button[type="reset"]').exists()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has the text "form.cancel"', () => {
|
||||||
|
expect(wrapper.find('button[type="reset"]').text()).toBe('form.reset')
|
||||||
|
})
|
||||||
|
|
||||||
|
it.skip('clears the email field on click', async () => {
|
||||||
|
wrapper.find('#input-group-1').find('input').setValue('someone@watches.tv')
|
||||||
|
wrapper.find('button[type="reset"]').trigger('click')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(wrapper.vm.form.email).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -0,0 +1,175 @@
|
|||||||
|
<template>
|
||||||
|
<b-row class="transaction-form">
|
||||||
|
<b-col xl="12" md="12">
|
||||||
|
<b-alert show dismissible variant="default" class="text-center">
|
||||||
|
<span class="alert-text h3 text-light" v-html="$t('form.attention')"></span>
|
||||||
|
</b-alert>
|
||||||
|
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||||
|
<!-- -<QrCode @set-transaction="setTransaction"></QrCode> -->
|
||||||
|
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
|
||||||
|
<b-form role="form" @submit.prevent="handleSubmit(onSubmit)" @reset="onReset">
|
||||||
|
<!-- <div>
|
||||||
|
<qrcode-drop-zone id="input-0" v-model="form.img"></qrcode-drop-zone>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
-->
|
||||||
|
<div>
|
||||||
|
<validation-provider
|
||||||
|
name="Email"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
email: true,
|
||||||
|
is_not: $store.state.email,
|
||||||
|
}"
|
||||||
|
v-slot="{ errors }"
|
||||||
|
>
|
||||||
|
<b-row>
|
||||||
|
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
|
||||||
|
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||||
|
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-input-group
|
||||||
|
id="input-group-1"
|
||||||
|
label="Empfänger:"
|
||||||
|
label-for="input-1"
|
||||||
|
description="We'll never share your email with anyone else."
|
||||||
|
size="lg"
|
||||||
|
class="mb-3"
|
||||||
|
>
|
||||||
|
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||||
|
<b-icon icon="envelope" class="display-3"></b-icon>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-input
|
||||||
|
id="input-1"
|
||||||
|
v-model="form.email"
|
||||||
|
type="email"
|
||||||
|
placeholder="E-Mail"
|
||||||
|
style="font-size: xx-large; padding-left: 20px"
|
||||||
|
></b-form-input>
|
||||||
|
</b-input-group>
|
||||||
|
</validation-provider>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<validation-provider
|
||||||
|
:name="$t('form.amount')"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
double: [2, $i18n.locale === 'de' ? ',' : '.'],
|
||||||
|
between: [0.01, balance],
|
||||||
|
}"
|
||||||
|
v-slot="{ errors }"
|
||||||
|
>
|
||||||
|
<b-row>
|
||||||
|
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
|
||||||
|
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||||
|
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-input-group
|
||||||
|
id="input-group-2"
|
||||||
|
label="Betrag:"
|
||||||
|
label-for="input-2"
|
||||||
|
size="lg"
|
||||||
|
class="mb-3"
|
||||||
|
>
|
||||||
|
<b-input-group-prepend class="p-2 d-none d-md-block">
|
||||||
|
<div class="h3 pt-3 pr-3">GDD</div>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-input
|
||||||
|
id="input-2"
|
||||||
|
v-model="form.amount"
|
||||||
|
type="number"
|
||||||
|
:lang="$i18n.locale"
|
||||||
|
:placeholder="$n(0.01)"
|
||||||
|
step="0.01"
|
||||||
|
style="font-size: xx-large; padding-left: 20px"
|
||||||
|
></b-form-input>
|
||||||
|
</b-input-group>
|
||||||
|
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
|
||||||
|
<b-input-group id="input-group-3">
|
||||||
|
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||||
|
<b-icon icon="chat-right-text" class="display-3"></b-icon>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
<b-form-textarea
|
||||||
|
rows="3"
|
||||||
|
v-model="form.memo"
|
||||||
|
class="pl-3"
|
||||||
|
style="font-size: x-large"
|
||||||
|
></b-form-textarea>
|
||||||
|
</b-input-group>
|
||||||
|
</validation-provider>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<b-row>
|
||||||
|
<b-col>
|
||||||
|
<b-button type="reset" variant="secondary" @click="onReset">
|
||||||
|
{{ $t('form.reset') }}
|
||||||
|
</b-button>
|
||||||
|
</b-col>
|
||||||
|
<b-col class="text-right">
|
||||||
|
<b-button type="submit" variant="success">
|
||||||
|
{{ $t('form.send_now') }}
|
||||||
|
</b-button>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
</b-form>
|
||||||
|
</validation-observer>
|
||||||
|
</b-card>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
// import QrCode from './QrCode'
|
||||||
|
// import { QrcodeDropZone } from 'vue-qrcode-reader'
|
||||||
|
import { BIcon } from 'bootstrap-vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TransactionForm',
|
||||||
|
components: {
|
||||||
|
BIcon,
|
||||||
|
// QrCode,
|
||||||
|
// QrcodeDropZone,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
balance: { type: Number, default: 0 },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
email: '',
|
||||||
|
amount: '',
|
||||||
|
memo: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSubmit() {
|
||||||
|
this.$emit('set-transaction', {
|
||||||
|
email: this.form.email,
|
||||||
|
amount: this.form.amount,
|
||||||
|
memo: this.form.memo,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onReset(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
this.form.email = ''
|
||||||
|
this.form.amount = ''
|
||||||
|
this.form.memo = ''
|
||||||
|
},
|
||||||
|
setTransaction(data) {
|
||||||
|
this.form.email = data.email
|
||||||
|
this.form.amount = data.amount
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
span.errors {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<b-row v-if="!error">
|
||||||
|
<b-col>
|
||||||
|
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||||
|
<div class="display-2 p-4">
|
||||||
|
{{ $t('form.thx') }}
|
||||||
|
<hr />
|
||||||
|
{{ $t('form.send_transaction_success') }}
|
||||||
|
</div>
|
||||||
|
<p class="text-center">
|
||||||
|
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||||
|
</p>
|
||||||
|
</b-card>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
<b-row v-else>
|
||||||
|
<b-col>
|
||||||
|
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||||
|
<div class="display-2 p-4">
|
||||||
|
{{ $t('form.sorry') }}
|
||||||
|
<hr />
|
||||||
|
{{ $t('form.send_transaction_error') }}
|
||||||
|
</div>
|
||||||
|
<p class="text-center">
|
||||||
|
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||||
|
</p>
|
||||||
|
</b-card>
|
||||||
|
</b-col>
|
||||||
|
</b-row>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TransactionResult',
|
||||||
|
props: {
|
||||||
|
error: { type: Boolean, default: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -24,12 +24,30 @@ describe('GddStatus', () => {
|
|||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it displays the ammount of GDD', () => {
|
describe('balance is loading', () => {
|
||||||
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD')
|
it('it displays em-dash as the ammount of GDD', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('— GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it displays em-dash as the ammount of GDT', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('— GDT')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it displays the ammount of GDT', () => {
|
describe('balance is loaded', () => {
|
||||||
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT')
|
beforeEach(() => {
|
||||||
|
wrapper.setProps({
|
||||||
|
pending: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it displays the ammount of GDD', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(0).text()).toEqual('1234 GDD')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('it displays the ammount of GDT', () => {
|
||||||
|
expect(wrapper.findAll('div.card-body').at(1).text()).toEqual('9876 GDT')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,24 +2,14 @@
|
|||||||
<div>
|
<div>
|
||||||
<b-row>
|
<b-row>
|
||||||
<b-col>
|
<b-col>
|
||||||
<stats-card
|
<b-card style="background-color: #ebebeba3 !important">
|
||||||
type="gradient-red"
|
{{ pending ? '—' : $n(balance) }} GDD
|
||||||
sub-title="balance_gdd"
|
</b-card>
|
||||||
class="mb-4 h1"
|
|
||||||
style="background-color: #ebebeba3 !important"
|
|
||||||
>
|
|
||||||
{{ $n(balance) }} GDD
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
</b-col>
|
||||||
<b-col>
|
<b-col>
|
||||||
<stats-card
|
<b-card class="lg-h2 text-right" style="background-color: #ebebeba3 !important">
|
||||||
type="gradient-orange"
|
{{ pending ? '—' : $n(GdtBalance) }} GDT
|
||||||
sub-title="balance_gdt"
|
</b-card>
|
||||||
class="mb-4 h1"
|
|
||||||
style="background-color: #ebebeba3 !important"
|
|
||||||
>
|
|
||||||
{{ $n(GdtBalance) }} GDT
|
|
||||||
</stats-card>
|
|
||||||
</b-col>
|
</b-col>
|
||||||
</b-row>
|
</b-row>
|
||||||
</div>
|
</div>
|
||||||
@ -31,6 +21,10 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
balance: { type: Number, default: 0 },
|
balance: { type: Number, default: 0 },
|
||||||
GdtBalance: { type: Number, default: 0 },
|
GdtBalance: { type: Number, default: 0 },
|
||||||
|
pending: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -88,11 +88,9 @@
|
|||||||
</b-card>
|
</b-card>
|
||||||
</b-collapse>
|
</b-collapse>
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
<b-list-group-item>
|
<div v-if="transactions.length === 0" class="mt-lg-4 text-center">
|
||||||
<b-alert v-if="transactions.length === 0" show variant="secondary">
|
<span>{{ $t('transaction.nullTransactions') }}</span>
|
||||||
<span class="alert-text">{{ $t('transaction.nullTransactions') }}</span>
|
</div>
|
||||||
</b-alert>
|
|
||||||
</b-list-group-item>
|
|
||||||
</b-list-group>
|
</b-list-group>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -97,7 +97,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<b-row class="my-4">
|
<b-row class="my-4">
|
||||||
<b-col cols="12">
|
<b-col cols="12">
|
||||||
<base-input
|
<base-input
|
||||||
@ -164,12 +163,7 @@ export default {
|
|||||||
email: '',
|
email: '',
|
||||||
agree: false,
|
agree: false,
|
||||||
},
|
},
|
||||||
rules: [
|
|
||||||
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
|
||||||
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
|
||||||
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
|
||||||
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
|
||||||
],
|
|
||||||
password: '',
|
password: '',
|
||||||
checkPassword: '',
|
checkPassword: '',
|
||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
@ -231,6 +225,14 @@ export default {
|
|||||||
emailFilled() {
|
emailFilled() {
|
||||||
return this.model.email !== ''
|
return this.model.email !== ''
|
||||||
},
|
},
|
||||||
|
rules() {
|
||||||
|
return [
|
||||||
|
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
||||||
|
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
||||||
|
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
||||||
|
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
||||||
|
]
|
||||||
|
},
|
||||||
passwordValidation() {
|
passwordValidation() {
|
||||||
const errors = []
|
const errors = []
|
||||||
for (const condition of this.rules) {
|
for (const condition of this.rules) {
|
||||||
|
|||||||
@ -90,12 +90,6 @@ export default {
|
|||||||
name: 'reset',
|
name: 'reset',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
rules: [
|
|
||||||
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
|
||||||
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
|
||||||
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
|
||||||
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
|
||||||
],
|
|
||||||
password: '',
|
password: '',
|
||||||
checkPassword: '',
|
checkPassword: '',
|
||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
@ -137,6 +131,14 @@ export default {
|
|||||||
passwordsFilled() {
|
passwordsFilled() {
|
||||||
return this.password !== '' && this.checkPassword !== ''
|
return this.password !== '' && this.checkPassword !== ''
|
||||||
},
|
},
|
||||||
|
rules() {
|
||||||
|
return [
|
||||||
|
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
||||||
|
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
||||||
|
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
||||||
|
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
||||||
|
]
|
||||||
|
},
|
||||||
passwordValidation() {
|
passwordValidation() {
|
||||||
const errors = []
|
const errors = []
|
||||||
for (const condition of this.rules) {
|
for (const condition of this.rules) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="header pb-8 pt-5 pt-lg-8 d-flex align-items-center profile-header"
|
class="header pb-8 pt-lg-4 d-flex align-items-center profile-header"
|
||||||
style="max-height: 200px"
|
style="max-height: 200px"
|
||||||
></div>
|
></div>
|
||||||
<b-container fluid class="mt--6">
|
<b-container fluid class="mt--6">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="header bg-gradient-info py-7 py-lg-8 pt-lg-9">
|
<div class="header py-7 py-lg-8 pt-lg-9">
|
||||||
<b-container>
|
<b-container>
|
||||||
<div class="header-body text-center mb-7">
|
<div class="header-body text-center mb-7">
|
||||||
<p class="h1">{{ $t('site.thx.title') }}</p>
|
<p class="h1">{{ $t('site.thx.title') }}</p>
|
||||||
@ -10,18 +10,6 @@
|
|||||||
<b-button to="/login">{{ $t('login') }}</b-button>
|
<b-button to="/login">{{ $t('login') }}</b-button>
|
||||||
</div>
|
</div>
|
||||||
</b-container>
|
</b-container>
|
||||||
<div class="separator separator-bottom separator-skew zindex-100">
|
|
||||||
<svg
|
|
||||||
x="0"
|
|
||||||
y="0"
|
|
||||||
viewBox="0 0 2560 100"
|
|
||||||
preserveAspectRatio="none"
|
|
||||||
version="1.1"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<polygon class="fill-default" points="2560 0 2560 100 0 100"></polygon>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Page content -->
|
<!-- Page content -->
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user