mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge pull request #415 from gradido/refactor-gdd-send
refactor: Split GddSend into Components
This commit is contained in:
commit
4a9533590c
@ -51,14 +51,11 @@ const communityAPI = {
|
||||
}
|
||||
return apiPost(CONFIG.COMMUNITY_API__URL + 'createCoins/', payload)
|
||||
}, */
|
||||
send: async (sessionId, email, amount, memo, targetDate) => {
|
||||
send: async (sessionId, data) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
amount,
|
||||
memo,
|
||||
target_date: targetDate,
|
||||
auto_sign: true,
|
||||
...data,
|
||||
}
|
||||
return apiPost(CONFIG.COMMUNITY_API_URL + 'sendCoins/', payload)
|
||||
},
|
||||
|
||||
@ -34,30 +34,5 @@ describe('AccountOverview', () => {
|
||||
it('has a transactions table', () => {
|
||||
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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -2,24 +2,36 @@
|
||||
<div>
|
||||
<base-header class="pb-4 pt-2 bg-transparent"></base-header>
|
||||
<b-container fluid class="p-2 mt-5">
|
||||
<gdd-status v-if="showTransactionList" :balance="balance" :gdt-balance="GdtBalance" />
|
||||
<gdd-status v-if="showContext" :balance="balance" :gdt-balance="GdtBalance" />
|
||||
<br />
|
||||
<gdd-send
|
||||
:balance="balance"
|
||||
:show-transaction-list="showTransactionList"
|
||||
@update-balance="updateBalance"
|
||||
@toggle-show-list="toggleShowList"
|
||||
/>
|
||||
<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 />
|
||||
<gdd-table
|
||||
v-if="showTransactionList"
|
||||
v-if="showContext"
|
||||
:transactions="transactions"
|
||||
:max="5"
|
||||
:timestamp="timestamp"
|
||||
: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>
|
||||
</div>
|
||||
</template>
|
||||
@ -28,6 +40,17 @@ import GddStatus from './AccountOverview/GddStatus.vue'
|
||||
import GddSend from './AccountOverview/GddSend.vue'
|
||||
import GddTable from './AccountOverview/GddTable.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 {
|
||||
name: 'Overview',
|
||||
@ -36,11 +59,16 @@ export default {
|
||||
GddSend,
|
||||
GddTable,
|
||||
GddTableFooter,
|
||||
TransactionForm,
|
||||
TransactionConfirmation,
|
||||
TransactionResult,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showTransactionList: true,
|
||||
timestamp: Date.now(),
|
||||
transactionData: EMPTY_TRANSACTION_DATA,
|
||||
error: false,
|
||||
currentTransactionStep: 0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@ -51,15 +79,30 @@ export default {
|
||||
},
|
||||
transactionCount: { type: Number, default: 0 },
|
||||
},
|
||||
computed: {
|
||||
showContext() {
|
||||
return this.currentTransactionStep === 0
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleShowList(bool) {
|
||||
this.showTransactionList = bool
|
||||
setTransaction(data) {
|
||||
data.target_date = new Date(Date.now()).toISOString()
|
||||
this.transactionData = { ...data }
|
||||
this.currentTransactionStep = 1
|
||||
},
|
||||
updateBalance(data) {
|
||||
this.$emit('update-balance', data.ammount)
|
||||
async sendTransaction() {
|
||||
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() {
|
||||
this.$emit('update-transactions')
|
||||
onReset() {
|
||||
this.transactionData = EMPTY_TRANSACTION_DATA
|
||||
this.currentTransactionStep = 0
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,29 +1,18 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import GddSend from './GddSend'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
describe('GddSend', () => {
|
||||
let wrapper
|
||||
|
||||
const state = {
|
||||
user: {
|
||||
balance: 1234,
|
||||
balance_gdt: 9876,
|
||||
},
|
||||
}
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
})
|
||||
|
||||
const mocks = {
|
||||
// $n: jest.fn((n) => n),
|
||||
$t: jest.fn((t) => t),
|
||||
$moment: jest.fn((m) => ({
|
||||
format: () => m,
|
||||
})),
|
||||
$store: {
|
||||
state: {
|
||||
sessionId: 1234,
|
||||
},
|
||||
},
|
||||
$i18n: {
|
||||
locale: jest.fn(() => 'en'),
|
||||
},
|
||||
@ -31,7 +20,7 @@ describe('GddSend', () => {
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(GddSend, { localVue, store, mocks })
|
||||
return mount(GddSend, { localVue, mocks })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
@ -42,88 +31,5 @@ describe('GddSend', () => {
|
||||
it('renders the component', () => {
|
||||
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>
|
||||
<div class="gdd-send">
|
||||
<b-row v-show="showTransactionList">
|
||||
<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>
|
||||
<slot :name="transactionSteps[currentTransactionStep]" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { QrcodeStream, QrcodeDropZone } from 'vue-qrcode-reader'
|
||||
import { BIcon } from 'bootstrap-vue'
|
||||
import communityAPI from '../../../apis/communityAPI.js'
|
||||
|
||||
export default {
|
||||
name: 'GddSent',
|
||||
components: {
|
||||
// QrcodeStream,
|
||||
// QrcodeDropZone,
|
||||
BIcon,
|
||||
},
|
||||
props: {
|
||||
balance: { type: Number, default: 0 },
|
||||
showTransactionList: { type: Boolean, default: true },
|
||||
},
|
||||
name: 'GddSend',
|
||||
data() {
|
||||
return {
|
||||
// scan: false,
|
||||
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,
|
||||
transactionSteps: ['transaction-form', 'transaction-confirmation', 'transaction-result'],
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
// 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
|
||||
})
|
||||
},
|
||||
props: {
|
||||
currentTransactionStep: { type: Number, default: 0 },
|
||||
},
|
||||
}
|
||||
</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>
|
||||
Loading…
x
Reference in New Issue
Block a user