mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into Feature--Profile-Page-with-data
This commit is contained in:
commit
4b3e32b544
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -212,7 +212,7 @@ jobs:
|
||||
report_name: Coverage Frontend
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
min_coverage: 18
|
||||
min_coverage: 19
|
||||
token: ${{ github.token }}
|
||||
|
||||
#test:
|
||||
|
||||
@ -156,6 +156,9 @@ class AppRequestsController extends AppController
|
||||
if($required_fields !== true) {
|
||||
return $this->returnJson($required_fields);
|
||||
}
|
||||
if(!isset($params['memo']) || strlen($params['memo']) < 5 || strlen($params['memo']) > 150) {
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'memo is not set or not in expected range [5;150]']);
|
||||
}
|
||||
$params['transaction_type'] = 'transfer';
|
||||
|
||||
$requestAnswear = $this->JsonRequestClient->sendRequest(json_encode($params), '/createTransaction');
|
||||
|
||||
@ -237,6 +237,11 @@ class TransactionSendCoinsController extends AppController
|
||||
$this->set('timeUsed', microtime(true) - $startTime);
|
||||
return;
|
||||
}
|
||||
if($answear_data['msg'] === 'memo is not set or not in expected range [5;150]') {
|
||||
$this->Flash->error(__('Ein Verwendungszweck zwischen 5 und 150 Zeichen wird benötig!'));
|
||||
$this->set('timeUsed', microtime(true) - $startTime);
|
||||
return;
|
||||
}
|
||||
} else if($answear_data['state'] === 'not found' && $answear_data['msg'] === 'receiver not found') {
|
||||
$this->Flash->error(__('Der Empfänger wurde nicht auf dem Login-Server gefunden, hat er sein Konto schon angelegt?'));
|
||||
$this->set('timeUsed', microtime(true) - $startTime);
|
||||
|
||||
@ -49,40 +49,49 @@ a,
|
||||
.copyright {
|
||||
color: #5a7b02;
|
||||
}
|
||||
gradido-global-color-text {
|
||||
.font1_2em {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.font2em {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.gradido-global-color-text {
|
||||
color: #3d443b;
|
||||
}
|
||||
gradido-global-color-accent {
|
||||
.gradido-global-color-accent {
|
||||
color: #047006;
|
||||
}
|
||||
gradido-global-color-6e0a9c9e {
|
||||
.gradido-global-color-6e0a9c9e {
|
||||
color: #000;
|
||||
}
|
||||
gradido-global-color-2d0fb154 {
|
||||
.gradido-global-color-2d0fb154 {
|
||||
color: #047006;
|
||||
}
|
||||
gradido-global-color-16efe88c {
|
||||
.gradido-global-color-16efe88c {
|
||||
color: #7ebc55;
|
||||
}
|
||||
gradido-global-color-1939326 {
|
||||
.gradido-global-color-1939326 {
|
||||
color: #f6fff6;
|
||||
}
|
||||
gradido-global-color-9d79fc1 {
|
||||
.gradido-global-color-9d79fc1 {
|
||||
color: #047006;
|
||||
}
|
||||
gradido-global-color-6347f4d {
|
||||
.gradido-global-color-6347f4d {
|
||||
color: #5a7b02;
|
||||
}
|
||||
gradido-global-color-4fbc19a {
|
||||
.gradido-global-color-4fbc19a {
|
||||
color: #014034;
|
||||
}
|
||||
gradido-global-color-d341874 {
|
||||
.gradido-global-color-d341874 {
|
||||
color: #b6d939;
|
||||
}
|
||||
gradido-global-color-619d338 {
|
||||
.gradido-global-color-619d338 {
|
||||
color: #8ebfb1;
|
||||
}
|
||||
gradido-global-color-44819a9 {
|
||||
.gradido-global-color-44819a9 {
|
||||
color: #026873;
|
||||
}
|
||||
.gradido-global-color-gray {
|
||||
color: #858383;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import CONFIG from '../config'
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import regeneratorRuntime from 'regenerator-runtime'
|
||||
|
||||
// control email-text sended with email verification code
|
||||
const EMAIL_TYPE = {
|
||||
@ -86,6 +88,16 @@ const loginAPI = {
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
updateLanguage: async (sessionId, email, language) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
update: {
|
||||
'User.language': language,
|
||||
},
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
}
|
||||
|
||||
export default loginAPI
|
||||
|
||||
95
frontend/src/components/LanguageSwitch.spec.js
Normal file
95
frontend/src/components/LanguageSwitch.spec.js
Normal file
@ -0,0 +1,95 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import LanguageSwitch from './LanguageSwitch'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
describe('LanguageSwitch', () => {
|
||||
let wrapper
|
||||
|
||||
const state = {
|
||||
sessionId: 1234,
|
||||
email: 'he@ho.he',
|
||||
language: null,
|
||||
}
|
||||
|
||||
const mocks = {
|
||||
$store: {
|
||||
state,
|
||||
commit: jest.fn(),
|
||||
},
|
||||
$i18n: {
|
||||
locale: 'en',
|
||||
},
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(LanguageSwitch, { localVue, mocks })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('with locales en and de', () => {
|
||||
describe('empty store', () => {
|
||||
it('shows English as default navigator langauge', () => {
|
||||
expect(wrapper.find('button.dropdown-toggle').text()).toBe('English - en')
|
||||
})
|
||||
|
||||
describe('navigator language is "de-DE"', () => {
|
||||
const mockNavigator = jest.fn(() => {
|
||||
return 'de'
|
||||
})
|
||||
|
||||
it('shows Deutsch as language ', async () => {
|
||||
wrapper.vm.getNavigatorLanguage = mockNavigator
|
||||
wrapper.vm.setCurrentLanguage()
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('button.dropdown-toggle').text()).toBe('Deutsch - de')
|
||||
})
|
||||
})
|
||||
|
||||
describe('navigator language is "es-ES" (not supported)', () => {
|
||||
const mockNavigator = jest.fn(() => {
|
||||
return 'es'
|
||||
})
|
||||
|
||||
it('shows English as language ', async () => {
|
||||
wrapper.vm.getNavigatorLanguage = mockNavigator
|
||||
wrapper.vm.setCurrentLanguage()
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('button.dropdown-toggle').text()).toBe('English - en')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('language "de" in store', () => {
|
||||
it('shows Deutsch as language', async () => {
|
||||
wrapper.vm.$store.state.language = 'de'
|
||||
wrapper.vm.setCurrentLanguage()
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('button.dropdown-toggle').text()).toBe('Deutsch - de')
|
||||
})
|
||||
})
|
||||
|
||||
describe('dropdown menu', () => {
|
||||
it('has English and German as languages to choose', () => {
|
||||
expect(wrapper.findAll('li')).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('has English as first language to choose', () => {
|
||||
expect(wrapper.findAll('li').at(0).text()).toBe('English')
|
||||
})
|
||||
|
||||
it('has German as second language to choose', () => {
|
||||
expect(wrapper.findAll('li').at(1).text()).toBe('Deutsch')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,22 +1,72 @@
|
||||
<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 size="sm" :text="currentLanguage.name + ' - ' + currentLanguage.code">
|
||||
<b-dropdown-item
|
||||
v-for="lang in locales"
|
||||
@click.prevent="saveLocale(lang.code)"
|
||||
:key="lang.code"
|
||||
>
|
||||
{{ lang.name }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { localeChanged } from 'vee-validate'
|
||||
import locales from '../locales/'
|
||||
import loginAPI from '../apis/loginAPI'
|
||||
|
||||
export default {
|
||||
name: 'language-switch',
|
||||
name: 'LanguageSwitch',
|
||||
data() {
|
||||
return {
|
||||
locales: locales,
|
||||
currentLanguage: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setLocale(locale) {
|
||||
this.$i18n.locale = locale
|
||||
this.$store.commit('language', this.$i18n.locale)
|
||||
this.currentLanguage = this.getLocaleObject(locale)
|
||||
localeChanged(locale)
|
||||
},
|
||||
async saveLocale(locale) {
|
||||
this.setLocale(locale)
|
||||
if (this.$store.state.sessionId && this.$store.state.email) {
|
||||
const result = await loginAPI.updateLanguage(
|
||||
this.$store.state.sessionId,
|
||||
this.$store.state.email,
|
||||
locale,
|
||||
)
|
||||
if (result.success) {
|
||||
// toast success message
|
||||
} else {
|
||||
// toast error message
|
||||
}
|
||||
}
|
||||
},
|
||||
getLocaleObject(code) {
|
||||
return this.locales.find((l) => l.code === code)
|
||||
},
|
||||
getNavigatorLanguage() {
|
||||
const lang = navigator.language
|
||||
if (lang) return lang.split('-')[0]
|
||||
return lang
|
||||
},
|
||||
setCurrentLanguage() {
|
||||
let locale = this.$store.state.language || this.getNavigatorLanguage() || 'en'
|
||||
let object = this.getLocaleObject(locale)
|
||||
if (!object) {
|
||||
locale = 'en'
|
||||
object = this.getLocaleObject(locale)
|
||||
}
|
||||
this.setLocale(locale)
|
||||
this.currentLanguage = object
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setCurrentLanguage()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -19,6 +19,7 @@ describe('SideBar', () => {
|
||||
state: {
|
||||
email: 'test@example.org',
|
||||
},
|
||||
commit: jest.fn(),
|
||||
},
|
||||
$i18n: {
|
||||
locale: 'en',
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
"de": "Deutsch",
|
||||
"en": "English"
|
||||
},
|
||||
"decay": "Vergänglichkeit",
|
||||
"form": {
|
||||
"cancel": "Abbrechen",
|
||||
"reset": "Zurücksetzen",
|
||||
@ -93,7 +94,9 @@
|
||||
},
|
||||
"thx": {
|
||||
"title": "Danke!",
|
||||
"subtitle": "Wir haben dir eine eMail gesendet."
|
||||
"email": "Wir haben dir eine eMail gesendet.",
|
||||
"reset": "Dein Passwort wurde geändert.",
|
||||
"register": "Du bist jetzt regisriert."
|
||||
},
|
||||
"overview":{
|
||||
"account_overview":"Kontoübersicht",
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
"de": "Deutsch",
|
||||
"en": "English"
|
||||
},
|
||||
"decay": "Decay",
|
||||
"form": {
|
||||
"cancel":"Cancel",
|
||||
"reset": "Reset",
|
||||
@ -93,7 +94,9 @@
|
||||
},
|
||||
"thx": {
|
||||
"title": "Thank you!",
|
||||
"subtitle": "We have sent you an email."
|
||||
"email": "We have sent you an email.",
|
||||
"reset": "Your password has been changed.",
|
||||
"register": "You are registred now."
|
||||
},
|
||||
"overview":{
|
||||
"account_overview":"Account overview",
|
||||
|
||||
16
frontend/src/locales/index.js
Normal file
16
frontend/src/locales/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
const locales = [
|
||||
{
|
||||
name: 'English',
|
||||
code: 'en',
|
||||
iso: 'en-US',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
name: 'Deutsch',
|
||||
code: 'de',
|
||||
iso: 'de-DE',
|
||||
enabled: true,
|
||||
},
|
||||
]
|
||||
|
||||
export default locales
|
||||
@ -33,8 +33,16 @@ const routes = [
|
||||
component: () => import('../views/Pages/Login.vue'),
|
||||
},
|
||||
{
|
||||
path: '/thx',
|
||||
path: '/thx/:comingFrom',
|
||||
component: () => import('../views/Pages/thx.vue'),
|
||||
beforeEnter: (to, from, next) => {
|
||||
const validFrom = ['password', 'reset', 'register']
|
||||
if (!validFrom.includes(from.path.split('/')[1])) {
|
||||
next({ path: '/login' })
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/password',
|
||||
|
||||
@ -18,7 +18,8 @@ export const mutations = {
|
||||
export const actions = {
|
||||
login: ({ dispatch, commit }, data) => {
|
||||
commit('sessionId', data.sessionId)
|
||||
commit('email', data.email)
|
||||
commit('email', data.user.email)
|
||||
commit('language', data.user.language)
|
||||
},
|
||||
logout: ({ commit, state }) => {
|
||||
commit('sessionId', null)
|
||||
@ -36,7 +37,7 @@ export const store = new Vuex.Store({
|
||||
state: {
|
||||
sessionId: null,
|
||||
email: '',
|
||||
language: 'en',
|
||||
language: null,
|
||||
modals: false,
|
||||
},
|
||||
getters: {},
|
||||
|
||||
@ -35,20 +35,37 @@ describe('Vuex store', () => {
|
||||
const commit = jest.fn()
|
||||
const state = {}
|
||||
|
||||
it('calls two commits', () => {
|
||||
login({ commit, state }, { sessionId: 1234, email: 'someone@there.is' })
|
||||
expect(commit).toHaveBeenCalledTimes(2)
|
||||
it('calls three commits', () => {
|
||||
login(
|
||||
{ commit, state },
|
||||
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||
)
|
||||
expect(commit).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
it('commits sessionId', () => {
|
||||
login({ commit, state }, { sessionId: 1234, email: 'someone@there.is' })
|
||||
login(
|
||||
{ commit, state },
|
||||
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||
)
|
||||
expect(commit).toHaveBeenNthCalledWith(1, 'sessionId', 1234)
|
||||
})
|
||||
|
||||
it('commits email', () => {
|
||||
login({ commit, state }, { sessionId: 1234, email: 'someone@there.is' })
|
||||
login(
|
||||
{ commit, state },
|
||||
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||
)
|
||||
expect(commit).toHaveBeenNthCalledWith(2, 'email', 'someone@there.is')
|
||||
})
|
||||
|
||||
it('commits language', () => {
|
||||
login(
|
||||
{ commit, state },
|
||||
{ sessionId: 1234, user: { email: 'someone@there.is', language: 'en' } },
|
||||
)
|
||||
expect(commit).toHaveBeenNthCalledWith(3, 'language', 'en')
|
||||
})
|
||||
})
|
||||
|
||||
describe('logout', () => {
|
||||
|
||||
@ -44,6 +44,9 @@ describe('DashboardLayoutGdd', () => {
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
mutations: {
|
||||
language: jest.fn(),
|
||||
},
|
||||
})
|
||||
|
||||
const Wrapper = () => {
|
||||
|
||||
@ -28,7 +28,7 @@ describe('AccountOverview', () => {
|
||||
})
|
||||
|
||||
it('has a transactions table', () => {
|
||||
expect(wrapper.find('gdd-table-stub').exists()).toBeTruthy()
|
||||
expect(wrapper.find('gdd-transaction-list-stub').exists()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
</template>
|
||||
</gdd-send>
|
||||
<hr />
|
||||
<gdd-table
|
||||
<gdd-transaction-list
|
||||
v-if="showContext"
|
||||
:transactions="transactions"
|
||||
:max="5"
|
||||
@ -36,15 +36,15 @@
|
||||
:transactionCount="transactionCount"
|
||||
@update-transactions="$emit('update-transactions')"
|
||||
/>
|
||||
<gdd-table-footer v-if="showContext" :count="transactionCount" />
|
||||
<gdd-transaction-list-footer v-if="showContext" :count="transactionCount" />
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
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 GddTransactionList from './AccountOverview/GddTransactionList.vue'
|
||||
import GddTransactionListFooter from './AccountOverview/GddTransactionListFooter.vue'
|
||||
import TransactionForm from './AccountOverview/GddSend/TransactionForm.vue'
|
||||
import TransactionConfirmation from './AccountOverview/GddSend/TransactionConfirmation.vue'
|
||||
import TransactionResult from './AccountOverview/GddSend/TransactionResult.vue'
|
||||
@ -62,8 +62,8 @@ export default {
|
||||
components: {
|
||||
GddStatus,
|
||||
GddSend,
|
||||
GddTable,
|
||||
GddTableFooter,
|
||||
GddTransactionList,
|
||||
GddTransactionListFooter,
|
||||
TransactionForm,
|
||||
TransactionConfirmation,
|
||||
TransactionResult,
|
||||
|
||||
@ -84,7 +84,22 @@
|
||||
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>
|
||||
</validation-provider>
|
||||
<validation-provider
|
||||
:rules="{
|
||||
required: true,
|
||||
min: 5,
|
||||
max: 150,
|
||||
}"
|
||||
:name="$t('form.memo')"
|
||||
v-slot="{ errors }"
|
||||
>
|
||||
<b-row>
|
||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</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-3">
|
||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||
<b-icon icon="chat-right-text" class="display-3"></b-icon>
|
||||
|
||||
@ -6,47 +6,26 @@
|
||||
:key="item.id"
|
||||
style="background-color: #ebebeba3 !important"
|
||||
>
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<b-icon
|
||||
v-if="item.type === 'send'"
|
||||
icon="arrow-left-circle"
|
||||
class="m-1 text-danger"
|
||||
font-scale="2"
|
||||
style="color: red"
|
||||
></b-icon>
|
||||
<b-icon
|
||||
v-else-if="item.type === 'receive'"
|
||||
icon="arrow-right-circle"
|
||||
class="m-1"
|
||||
font-scale="2"
|
||||
style="color: green"
|
||||
></b-icon>
|
||||
<b-icon
|
||||
v-else-if="item.type === 'creation'"
|
||||
icon="gift"
|
||||
class="m-1"
|
||||
font-scale="2"
|
||||
style="color: orange"
|
||||
></b-icon>
|
||||
<b-icon
|
||||
v-else
|
||||
icon="droplet-half"
|
||||
class="m-1"
|
||||
font-scale="2"
|
||||
style="color: orange"
|
||||
></b-icon>
|
||||
<h1 class="">
|
||||
<span v-if="item.type === 'receive' || item.type === 'creation'">+</span>
|
||||
<span v-else>-</span>
|
||||
<div class="d-flex" v-b-toggle="'a' + item.date + ''">
|
||||
<div style="width: 8%">
|
||||
<b-icon :icon="getIcon(item)" :class="getClass(item)" />
|
||||
</div>
|
||||
<div class="font1_2em pr-2 text-right" style="width: 22%">
|
||||
<span>{{ getOperator(item) }}</span>
|
||||
{{ $n(item.balance) }}
|
||||
<small>GDD</small>
|
||||
</h1>
|
||||
<h2 class="text-muted">{{ item.name }}</h2>
|
||||
<b-button v-b-toggle="'a' + item.transaction_id" variant="secondary">
|
||||
<b>i</b>
|
||||
</b-button>
|
||||
</div>
|
||||
<div class="font1_2em text-left pl-2" style="width: 65%">
|
||||
{{ item.name }}
|
||||
<small>{{ item.name ? '' : $t('decay') }}</small>
|
||||
<div class="text-sm">{{ $moment(item.date).format('DD.MM.YYYY - HH:mm:ss') }}</div>
|
||||
</div>
|
||||
<div class="text-right" style="width: 5%">
|
||||
<b-button class="btn-sm">
|
||||
<b>i</b>
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
<b-collapse :id="'a' + item.transaction_id" class="mt-2">
|
||||
<b-collapse :id="'a' + item.date + ''" class="mt-2">
|
||||
<b-card>
|
||||
<b-list-group>
|
||||
<b-list-group-item v-if="item.type === 'send'">
|
||||
@ -79,16 +58,16 @@
|
||||
{{ item.memo }}
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<b-button v-b-toggle="'collapse-1-inner' + item.transaction_id" variant="secondary">
|
||||
<b-button v-b-toggle="'collapse-1-inner' + item.date" variant="secondary">
|
||||
{{ $t('transaction.more') }}
|
||||
</b-button>
|
||||
<b-collapse :id="'collapse-1-inner' + item.transaction_id" class="mt-2">
|
||||
<b-collapse :id="'collapse-1-inner' + item.date" class="mt-2">
|
||||
<b-card>{{ item }}</b-card>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
</b-collapse>
|
||||
</b-list-group-item>
|
||||
<div v-if="transactions.length === 0" class="mt-lg-4 text-center">
|
||||
<div v-if="transactions.length === 0" class="mt-4 text-center">
|
||||
<span>{{ $t('transaction.nullTransactions') }}</span>
|
||||
</div>
|
||||
</b-list-group>
|
||||
@ -96,8 +75,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const iconsByType = {
|
||||
send: { icon: 'arrow-left-circle', classes: 'text-danger', operator: '-' },
|
||||
receive: { icon: 'arrow-right-circle', classes: 'gradido-global-color-accent', operator: '+' },
|
||||
creation: { icon: 'gift', classes: 'gradido-global-color-accent', operator: '+' },
|
||||
decay: { icon: 'droplet-half', classes: 'gradido-global-color-gray', operator: '-' },
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'GddTable',
|
||||
name: 'gdd-transaction-list',
|
||||
props: {
|
||||
transactions: { default: [] },
|
||||
max: { type: Number, default: 1000 },
|
||||
@ -121,6 +107,24 @@ export default {
|
||||
updateTransactions() {
|
||||
this.$emit('update-transactions')
|
||||
},
|
||||
getIcon(item) {
|
||||
const icon = iconsByType[item.type]
|
||||
if (icon) return icon.icon
|
||||
const thing = new Error('no item to given type')
|
||||
thing()
|
||||
},
|
||||
getClass(item) {
|
||||
const icon = iconsByType[item.type]
|
||||
if (icon) return icon.classes + ' m-mb-1 font2em'
|
||||
const thing = new Error('no item to given type')
|
||||
thing()
|
||||
},
|
||||
getOperator(item) {
|
||||
const icon = iconsByType[item.type]
|
||||
if (icon) return icon.operator
|
||||
const thing = new Error('no item to given type')
|
||||
thing()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GddTableFooter',
|
||||
name: 'GddTransactionListFooter',
|
||||
props: {
|
||||
count: { count: Number },
|
||||
},
|
||||
@ -62,7 +62,7 @@ export default {
|
||||
async onSubmit() {
|
||||
const result = await loginAPI.sendEmail(this.form.email)
|
||||
if (result.success) {
|
||||
this.$router.push({ path: '/thx', params: { id: 'resetmail' } })
|
||||
this.$router.push('/thx/password')
|
||||
} else {
|
||||
alert(result.result)
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
import flushPromises from 'flush-promises'
|
||||
|
||||
import Login from './Login'
|
||||
@ -16,20 +15,12 @@ describe('Login', () => {
|
||||
$t: jest.fn((t) => t),
|
||||
}
|
||||
|
||||
const state = {
|
||||
loginfail: false,
|
||||
}
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
})
|
||||
|
||||
const stubs = {
|
||||
RouterLink: RouterLinkStub,
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(Login, { localVue, mocks, store, stubs })
|
||||
return mount(Login, { localVue, mocks, stubs })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
|
||||
@ -122,7 +122,7 @@ export default {
|
||||
if (result.success) {
|
||||
this.$store.dispatch('login', {
|
||||
sessionId: result.result.data.session_id,
|
||||
email: this.model.email,
|
||||
user: result.result.data.user,
|
||||
})
|
||||
this.$router.push('/overview')
|
||||
loader.hide()
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
import flushPromises from 'flush-promises'
|
||||
|
||||
import Register from './Register'
|
||||
@ -16,20 +15,12 @@ describe('Register', () => {
|
||||
$t: jest.fn((t) => t),
|
||||
}
|
||||
|
||||
const state = {
|
||||
// loginfail: false,
|
||||
}
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
})
|
||||
|
||||
const stubs = {
|
||||
RouterLink: RouterLinkStub,
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(Register, { localVue, mocks, store, stubs })
|
||||
return mount(Register, { localVue, mocks, stubs })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
|
||||
@ -192,7 +192,7 @@ export default {
|
||||
this.model.firstname = ''
|
||||
this.model.lastname = ''
|
||||
this.password = ''
|
||||
this.$router.push('/thx')
|
||||
this.$router.push('/thx/register')
|
||||
} else {
|
||||
this.showError = true
|
||||
this.messageError = result.result.message
|
||||
|
||||
@ -107,7 +107,13 @@ export default {
|
||||
const result = await loginAPI.changePassword(this.sessionId, this.email, this.password)
|
||||
if (result.success) {
|
||||
this.password = ''
|
||||
this.$router.push('/thx')
|
||||
/*
|
||||
this.$store.dispatch('login', {
|
||||
sessionId: result.result.data.session_id,
|
||||
email: result.result.data.user.email,
|
||||
})
|
||||
*/
|
||||
this.$router.push('/thx/reset')
|
||||
} else {
|
||||
alert(result.result.message)
|
||||
}
|
||||
|
||||
28
frontend/src/views/Pages/UserProfile.vue
Normal file
28
frontend/src/views/Pages/UserProfile.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="header pb-8 pt-5 pt-lg-8 d-flex align-items-center profile-header">
|
||||
<b-container fluid></b-container>
|
||||
</div>
|
||||
|
||||
<b-container fluid class="mt--6">
|
||||
<b-row>
|
||||
<b-col xl="12" class="order-xl-2 mb-5">
|
||||
<user-card :balance="balance"></user-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import UserCard from './UserProfile/UserCard.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UserCard,
|
||||
},
|
||||
props: {
|
||||
balance: { type: Number, default: 0 },
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
@ -3,7 +3,7 @@
|
||||
<b-container fluid>
|
||||
<b-row>
|
||||
<b-col class="order-xl-1">
|
||||
<gdd-table
|
||||
<gdd-transaction-list
|
||||
:timestamp="timestamp"
|
||||
:transactionCount="transactionCount"
|
||||
:transactions="transactions"
|
||||
@ -15,11 +15,11 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import GddTable from '../../views/Pages/AccountOverview/GddTable.vue'
|
||||
import GddTransactionList from './AccountOverview/GddTransactionList.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GddTable,
|
||||
GddTransactionList,
|
||||
},
|
||||
props: {
|
||||
transactions: {
|
||||
|
||||
@ -5,12 +5,48 @@
|
||||
<b-container>
|
||||
<div class="header-body text-center mb-7">
|
||||
<p class="h1">{{ $t('site.thx.title') }}</p>
|
||||
<p class="h4">{{ $t('site.thx.subtitle') }}</p>
|
||||
<p class="h4">{{ $t(displaySetup.subtitle) }}</p>
|
||||
<hr />
|
||||
<b-button to="/login">{{ $t('login') }}</b-button>
|
||||
<b-button :to="displaySetup.linkTo">{{ $t(displaySetup.button) }}</b-button>
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
<!-- Page content -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
const textFields = {
|
||||
password: {
|
||||
subtitle: 'site.thx.email',
|
||||
button: 'login',
|
||||
linkTo: '/login',
|
||||
},
|
||||
reset: {
|
||||
subtitle: 'site.thx.reset',
|
||||
button: 'login',
|
||||
linkTo: '/login',
|
||||
},
|
||||
register: {
|
||||
subtitle: 'site.thx.register',
|
||||
button: 'site.login.signin',
|
||||
linkTo: '/overview',
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Thx',
|
||||
data() {
|
||||
return {
|
||||
displaySetup: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setDisplaySetup(from) {
|
||||
this.displaySetup = textFields[this.$route.params.comingFrom]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setDisplaySetup()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -108,6 +108,9 @@ Poco::JSON::Object* JsonCreateTransaction::transfer(Poco::Dynamic::Var params)
|
||||
else {
|
||||
result = stateError("parameter format unknown");
|
||||
}
|
||||
if (mMemo.size() < 5 || mMemo.size() > 150) {
|
||||
result = stateError("memo is not set or not in expected range [5;150]");
|
||||
}
|
||||
if (result) {
|
||||
mm->releaseMemory(target_pubkey);
|
||||
return result;
|
||||
|
||||
@ -31,7 +31,8 @@ namespace model {
|
||||
TRANSACTION_VALID_INVALID_AMOUNT,
|
||||
TRANSACTION_VALID_INVALID_PUBKEY,
|
||||
TRANSACTION_VALID_INVALID_GROUP_ALIAS,
|
||||
TRANSACTION_VALID_INVALID_SIGN
|
||||
TRANSACTION_VALID_INVALID_SIGN,
|
||||
TRANSACTION_VALID_INVALID_MEMO
|
||||
};
|
||||
const char* TransactionValidationToString(TransactionValidation result);
|
||||
|
||||
|
||||
@ -186,6 +186,10 @@ namespace model {
|
||||
addError(new Error(function_name, "sender and receiver are the same"));
|
||||
return TRANSACTION_VALID_INVALID_PUBKEY;
|
||||
}
|
||||
if (mMemo.size() < 5 || mMemo.size() > 150) {
|
||||
addError(new Error(function_name, "memo is not set or not in expected range [5;150]"));
|
||||
return TRANSACTION_VALID_INVALID_MEMO;
|
||||
}
|
||||
return TRANSACTION_VALID_OK;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user