diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4f887aa14..cf0b061ef 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -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:
diff --git a/community_server/src/Controller/AppRequestsController.php b/community_server/src/Controller/AppRequestsController.php
index 12ea77d0b..4d70a68b1 100644
--- a/community_server/src/Controller/AppRequestsController.php
+++ b/community_server/src/Controller/AppRequestsController.php
@@ -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');
diff --git a/community_server/src/Controller/TransactionSendCoinsController.php b/community_server/src/Controller/TransactionSendCoinsController.php
index 033e2343f..1018309cc 100644
--- a/community_server/src/Controller/TransactionSendCoinsController.php
+++ b/community_server/src/Controller/TransactionSendCoinsController.php
@@ -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);
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index d44d64ab3..a6613bec1 100755
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -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;
+}
diff --git a/frontend/src/apis/loginAPI.js b/frontend/src/apis/loginAPI.js
index f5b0c57f5..55e32e6dd 100644
--- a/frontend/src/apis/loginAPI.js
+++ b/frontend/src/apis/loginAPI.js
@@ -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
diff --git a/frontend/src/components/LanguageSwitch.spec.js b/frontend/src/components/LanguageSwitch.spec.js
new file mode 100644
index 000000000..14dc978ac
--- /dev/null
+++ b/frontend/src/components/LanguageSwitch.spec.js
@@ -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')
+ })
+ })
+ })
+ })
+})
diff --git a/frontend/src/components/LanguageSwitch.vue b/frontend/src/components/LanguageSwitch.vue
index 0fad036a6..2b160b3e3 100644
--- a/frontend/src/components/LanguageSwitch.vue
+++ b/frontend/src/components/LanguageSwitch.vue
@@ -1,22 +1,72 @@