diff --git a/admin/.dockerignore b/admin/.dockerignore index 88249539f..1ddda051a 100644 --- a/admin/.dockerignore +++ b/admin/.dockerignore @@ -1,3 +1,4 @@ node_modules .git -.gitignore \ No newline at end of file +.gitignore +!.eslintignore \ No newline at end of file diff --git a/admin/.eslintignore b/admin/.eslintignore index 433390392..94934f9e7 100644 --- a/admin/.eslintignore +++ b/admin/.eslintignore @@ -1,4 +1,3 @@ -node_modules -coverage -**/*.min.js -dist \ No newline at end of file +node_modules/ +dist/ +coverage/ \ No newline at end of file diff --git a/admin/.eslintrc.js b/admin/.eslintrc.js index 96c602ef3..73dce291f 100644 --- a/admin/.eslintrc.js +++ b/admin/.eslintrc.js @@ -8,9 +8,20 @@ module.exports = { parserOptions: { parser: 'babel-eslint', }, - extends: ['standard', 'plugin:vue/essential', 'plugin:prettier/recommended'], + extends: [ + 'standard', + 'plugin:vue/essential', + 'plugin:prettier/recommended', + 'plugin:@intlify/vue-i18n/recommended', + ], // required to lint *.vue files plugins: ['vue', 'prettier', 'jest'], + overrides: [ + { + files: ['*.json'], + extends: ['plugin:@intlify/vue-i18n/recommended'], + }, + ], // add your custom rules here rules: { 'no-console': ['error'], @@ -22,6 +33,17 @@ module.exports = { allowBinding: false, }, ], + '@intlify/vue-i18n/no-dynamic-keys': 'error', + '@intlify/vue-i18n/no-unused-keys': [ + 'error', + { + src: './src', + extensions: ['.js', '.vue'], + ignores: [], + enableFix: false, + }, + ], + '@intlify/vue-i18n/no-missing-keys-in-other-locales': 'error', 'prettier/prettier': [ 'error', { @@ -29,4 +51,12 @@ module.exports = { }, ], }, + settings: { + 'vue-i18n': { + localeDir: './src/locales/*.json', + // Specify the version of `vue-i18n` you are using. + // If not specified, the message will be parsed twice. + messageSyntaxVersion: '^8.26.5', + }, + }, } diff --git a/admin/package.json b/admin/package.json index a46dc1fd6..2b4be2851 100644 --- a/admin/package.json +++ b/admin/package.json @@ -12,11 +12,10 @@ "build": "vue-cli-service build", "dev": "yarn run serve", "analyse-bundle": "yarn build && webpack-bundle-analyzer dist/webpack.stats.json", - "lint": "eslint --max-warnings=0 --ext .js,.vue .", + "lint": "eslint --max-warnings=0 --ext .js,.vue,.json .", "stylelint": "stylelint --max-warnings=0 '**/*.{scss,vue}'", - "i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'", "test": "TZ=UTC jest --coverage", - "locales": "scripts/missing-keys.sh && scripts/sort.sh" + "locales": "scripts/sort.sh" }, "dependencies": { "@babel/core": "^7.15.8", @@ -52,6 +51,7 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.15.8", + "@intlify/eslint-plugin-vue-i18n": "^1.4.0", "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-eslint": "~4.5.0", "@vue/cli-service": "~4.5.0", diff --git a/admin/src/components/ContentFooter.vue b/admin/src/components/ContentFooter.vue index 510318e61..c10e53596 100644 --- a/admin/src/components/ContentFooter.vue +++ b/admin/src/components/ContentFooter.vue @@ -4,24 +4,24 @@ diff --git a/admin/src/components/CreationTransactionListFormular.spec.js b/admin/src/components/CreationTransactionListFormular.spec.js index 5acff8ab7..fb137e516 100644 --- a/admin/src/components/CreationTransactionListFormular.spec.js +++ b/admin/src/components/CreationTransactionListFormular.spec.js @@ -6,32 +6,30 @@ const localVue = global.localVue const apolloQueryMock = jest.fn().mockResolvedValue({ data: { - transactionList: { - transactions: [ - { - id: 1, - amount: 100, - balanceDate: 0, - creationDate: new Date(), - memo: 'Testing', - linkedUser: { - firstName: 'Gradido', - lastName: 'Akademie', - }, + creationTransactionList: [ + { + id: 1, + amount: 100, + balanceDate: 0, + creationDate: new Date(), + memo: 'Testing', + linkedUser: { + firstName: 'Gradido', + lastName: 'Akademie', }, - { - id: 2, - amount: 200, - balanceDate: 0, - creationDate: new Date(), - memo: 'Testing 2', - linkedUser: { - firstName: 'Gradido', - lastName: 'Akademie', - }, + }, + { + id: 2, + amount: 200, + balanceDate: 0, + creationDate: new Date(), + memo: 'Testing 2', + linkedUser: { + firstName: 'Gradido', + lastName: 'Akademie', }, - ], - }, + }, + ], }, }) @@ -67,7 +65,6 @@ describe('CreationTransactionListFormular', () => { currentPage: 1, pageSize: 25, order: 'DESC', - onlyCreations: true, userId: 1, }, }), diff --git a/admin/src/components/CreationTransactionListFormular.vue b/admin/src/components/CreationTransactionListFormular.vue index 0b78ca4b8..ce2b136a4 100644 --- a/admin/src/components/CreationTransactionListFormular.vue +++ b/admin/src/components/CreationTransactionListFormular.vue @@ -5,7 +5,7 @@ diff --git a/frontend/src/components/DecayInformations/DecayInformation-Decay.vue b/frontend/src/components/DecayInformations/DecayInformation-Decay.vue index 19aac9e98..6abacd2b8 100644 --- a/frontend/src/components/DecayInformations/DecayInformation-Decay.vue +++ b/frontend/src/components/DecayInformations/DecayInformation-Decay.vue @@ -13,8 +13,8 @@
- {{ (Number(balance) - Number(decay.decay)) | GDD }} - {{ decay.decay | GDD }} = + {{ (Number(balance) - Number(decay)) | GDD }} + {{ decay | GDD }} {{ $t('math.equal') }} {{ balance | GDD }}
@@ -27,9 +27,11 @@ export default { props: { balance: { type: String, + required: true, }, decay: { - type: Object, + type: String, + required: true, }, }, } diff --git a/frontend/src/components/DecayInformations/DecayInformation-DecayStartblock.vue b/frontend/src/components/DecayInformations/DecayInformation-DecayStartblock.vue index 2ee9ecc2c..5802bfb4b 100644 --- a/frontend/src/components/DecayInformations/DecayInformation-DecayStartblock.vue +++ b/frontend/src/components/DecayInformations/DecayInformation-DecayStartblock.vue @@ -4,12 +4,11 @@
{{ $t('decay.Starting_block_decay') }}
-
{{ $t('decay.decay_introduced') }} :
+
{{ $t('decay.decay_introduced') }}
{{ $d(new Date(decay.start), 'long') }} - {{ $i18n.locale === 'de' ? 'Uhr' : '' }}
@@ -28,7 +27,8 @@
- {{ $t(`decay.${typeId.toLowerCase()}`) }} + + {{ $t(`decay.types.${typeId.toLowerCase()}`) }} {{ amount | GDD }} diff --git a/frontend/src/components/DecayInformations/DecayInformation-Long.vue b/frontend/src/components/DecayInformations/DecayInformation-Long.vue index b5e1bbbe5..50e3d6697 100644 --- a/frontend/src/components/DecayInformations/DecayInformation-Long.vue +++ b/frontend/src/components/DecayInformations/DecayInformation-Long.vue @@ -15,7 +15,6 @@
{{ $d(new Date(decay.start), 'long') }} - {{ $i18n.locale === 'de' ? 'Uhr' : '' }}
@@ -44,7 +43,8 @@ - {{ $t(`decay.${typeId.toLowerCase()}`) }} + + {{ $t(`decay.types.${typeId.toLowerCase()}`) }} {{ amount | GDD }} @@ -82,7 +82,8 @@ export default { const result = [] order.forEach((timeSpan) => { if (this.duration[timeSpan] > 0) { - const locale = this.$t(`decay.${timeSpan}`) + // eslint-disable-next-line @intlify/vue-i18n/no-dynamic-keys + const locale = this.$t(`time.${timeSpan}`) result.push(`${this.duration[timeSpan]} ${locale}`) } }) diff --git a/frontend/src/components/DecayInformations/DecayInformation-Short.vue b/frontend/src/components/DecayInformations/DecayInformation-Short.vue index 1cd0a2d09..ba1f16d72 100644 --- a/frontend/src/components/DecayInformations/DecayInformation-Short.vue +++ b/frontend/src/components/DecayInformations/DecayInformation-Short.vue @@ -1,6 +1,6 @@ diff --git a/frontend/src/components/TransactionRows/DateRow.vue b/frontend/src/components/TransactionRows/DateRow.vue index 5daccfa69..0c72907fe 100644 --- a/frontend/src/components/TransactionRows/DateRow.vue +++ b/frontend/src/components/TransactionRows/DateRow.vue @@ -2,12 +2,11 @@
-
{{ $t('form.date') }}
+
{{ diffNow ? $t('gdd_per_link.expired') : $t('form.date') }}
- {{ $d(new Date(balanceDate), 'long') }} - {{ $i18n.locale === 'de' ? 'Uhr' : '' }} + {{ dateString }}
@@ -17,10 +16,22 @@ export default { name: 'DateRow', props: { - balanceDate: { + date: { type: String, required: true, }, + diffNow: { + type: Boolean, + required: false, + default: false, + }, + }, + computed: { + dateString() { + return this.diffNow + ? this.$moment(this.date).locale(this.$i18n.locale).fromNow() + : this.$d(new Date(this.date), 'long') + }, }, } diff --git a/frontend/src/components/TransactionRows/DecayRow.vue b/frontend/src/components/TransactionRows/DecayRow.vue index 92d79ef4b..f853d9f93 100644 --- a/frontend/src/components/TransactionRows/DecayRow.vue +++ b/frontend/src/components/TransactionRows/DecayRow.vue @@ -23,7 +23,7 @@ export default { }, props: { decay: { - type: Object, + type: String, required: false, }, }, diff --git a/frontend/src/components/TransactionRows/MemoRow.vue b/frontend/src/components/TransactionRows/MemoRow.vue index ef79fb38e..26b421bf9 100644 --- a/frontend/src/components/TransactionRows/MemoRow.vue +++ b/frontend/src/components/TransactionRows/MemoRow.vue @@ -16,7 +16,7 @@ export default { props: { memo: { type: String, - required: false, + required: true, }, }, } diff --git a/frontend/src/components/Transactions/TransactionCreation.vue b/frontend/src/components/Transactions/TransactionCreation.vue index 43178e5f2..bb131d39a 100644 --- a/frontend/src/components/Transactions/TransactionCreation.vue +++ b/frontend/src/components/Transactions/TransactionCreation.vue @@ -18,10 +18,10 @@ - + - +
diff --git a/frontend/src/components/Transactions/TransactionDecay.vue b/frontend/src/components/Transactions/TransactionDecay.vue index 4038e782f..2f235502a 100644 --- a/frontend/src/components/Transactions/TransactionDecay.vue +++ b/frontend/src/components/Transactions/TransactionDecay.vue @@ -20,8 +20,8 @@ - - + + diff --git a/frontend/src/components/Transactions/TransactionLink.vue b/frontend/src/components/Transactions/TransactionLink.vue deleted file mode 100644 index 5c261adbf..000000000 --- a/frontend/src/components/Transactions/TransactionLink.vue +++ /dev/null @@ -1,70 +0,0 @@ - - diff --git a/frontend/src/components/Transactions/TransactionLinkSummary.spec.js b/frontend/src/components/Transactions/TransactionLinkSummary.spec.js new file mode 100644 index 000000000..1f2a4388c --- /dev/null +++ b/frontend/src/components/Transactions/TransactionLinkSummary.spec.js @@ -0,0 +1,230 @@ +import { mount } from '@vue/test-utils' +import TransactionLinksSummary from './TransactionLinkSummary' +import { listTransactionLinks } from '@/graphql/queries' +import { toastErrorSpy } from '@test/testSetup' + +const localVue = global.localVue + +const apolloQueryMock = jest.fn() + +const mocks = { + $i18n: { + locale: 'en', + }, + $t: jest.fn((t) => t), + $tc: jest.fn((tc) => tc), + $apollo: { + query: apolloQueryMock, + }, +} + +const propsData = { + amount: '123', + decay: { + decay: '-0.2038314055482643084', + start: '2022-02-25T07:29:26.000Z', + end: '2022-02-28T13:55:47.000Z', + duration: 282381, + }, + transactionLinkCount: 4, +} + +describe('TransactionLinkSummary', () => { + let wrapper + + const Wrapper = () => { + return mount(TransactionLinksSummary, { localVue, mocks, propsData }) + } + + describe('mount', () => { + beforeEach(() => { + apolloQueryMock.mockResolvedValue({ + data: { + listTransactionLinks: [ + { + amount: '75', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 86, + memo: + 'Hokuspokus Haselnuss, Vogelbein und Fliegenfuß, damit der Trick gelingen muss!', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + { + amount: '85', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 107, + memo: 'Mäusespeck und Katzenbuckel, Tricks und Tracks und Zauberkugel!', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + { + amount: '95', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 92, + memo: + 'Abrakadabra 1,2,3, die Sonne kommt herbei. Schweinepups und Spuckebrei, der Regen ist vorbei.', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + { + amount: '150', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 16, + memo: + 'Abrakadabra 1,2,3 was verschwunden ist komme herbei.Wieseldreck und Schweinemist, zaubern das ist keine List.', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + ], + }, + }) + + wrapper = Wrapper() + }) + + it('renders the component transaction-slot-link', () => { + expect(wrapper.find('div.transaction-slot-link').exists()).toBe(true) + }) + + it('has a component CollapseLinksList', () => { + expect(wrapper.findComponent({ name: 'CollapseLinksList' }).exists()).toBe(true) + }) + + it('calls the API to get the list transaction links', () => { + expect(apolloQueryMock).toBeCalledWith({ + query: listTransactionLinks, + variables: { + currentPage: 1, + }, + fetchPolicy: 'network-only', + }) + }) + + it('has four transactionLinks', () => { + expect(wrapper.vm.transactionLinks).toHaveLength(4) + }) + + describe('reset transaction links', () => { + beforeEach(async () => { + jest.clearAllMocks() + await wrapper.setData({ + currentPage: 0, + pending: false, + pageSize: 5, + }) + }) + + it('reloads transaction links', () => { + expect(apolloQueryMock).toBeCalledWith({ + query: listTransactionLinks, + variables: { + currentPage: 1, + }, + fetchPolicy: 'network-only', + }) + }) + + it('emits update transactions', () => { + expect(wrapper.emitted('update-transactions')).toBeTruthy() + }) + + it('has four transaction links in list', () => { + expect(wrapper.vm.transactionLinks).toHaveLength(4) + }) + }) + + describe('load more transaction links', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloQueryMock.mockResolvedValue({ + data: { + listTransactionLinks: [ + { + amount: '76', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 87, + memo: + 'Hat jemand die Nummer von der Hexe aus Schneewittchen? Ich bräuchte mal ein paar Äpfel.', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + { + amount: '86', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 108, + memo: + 'Die Windfahn´ krächzt am Dach, Der Uhu im Geklüfte; Was wispert wie ein Ach Verhallend in die Lüfte?', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + { + amount: '96', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 93, + memo: + 'Verschlafen kräht der Hahn, Ein Blitz noch, und ein trüber, Umwölbter Tag bricht an – Walpurgisnacht vorüber!', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + { + amount: '150', + code: 'ce28664b5308c17f931c0367', + createdAt: '2022-03-16T14:22:40.000Z', + holdAvailableAmount: '5.13109484759482747111', + id: 17, + memo: 'Eene meene Flaschenschrank, fertig ist der Hexentrank!', + redeemedAt: null, + validUntil: '2022-03-30T14:22:40.000Z', + }, + ], + }, + }) + await wrapper.setData({ + currentPage: 2, + pending: false, + pageSize: 5, + }) + }) + + it('has eight transactionLinks', () => { + expect(wrapper.vm.transactionLinks).toHaveLength(8) + }) + + it('loads more transaction links', () => { + expect(apolloQueryMock).toBeCalledWith({ + query: listTransactionLinks, + variables: { + currentPage: 2, + }, + fetchPolicy: 'network-only', + }) + }) + }) + + describe('loads transaction links with error', () => { + beforeEach(() => { + apolloQueryMock.mockRejectedValue({ message: 'OUCH!' }) + wrapper = Wrapper() + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('OUCH!') + }) + }) + }) +}) diff --git a/frontend/src/components/Transactions/TransactionLinkSummary.vue b/frontend/src/components/Transactions/TransactionLinkSummary.vue new file mode 100644 index 000000000..3f80bfd18 --- /dev/null +++ b/frontend/src/components/Transactions/TransactionLinkSummary.vue @@ -0,0 +1,117 @@ + + diff --git a/frontend/src/components/Transactions/TransactionReceive.vue b/frontend/src/components/Transactions/TransactionReceive.vue index e9dc23cdb..eade4a30c 100644 --- a/frontend/src/components/Transactions/TransactionReceive.vue +++ b/frontend/src/components/Transactions/TransactionReceive.vue @@ -19,10 +19,10 @@ - + - + diff --git a/frontend/src/components/Transactions/TransactionSend.vue b/frontend/src/components/Transactions/TransactionSend.vue index 18112f8e1..8183a5734 100644 --- a/frontend/src/components/Transactions/TransactionSend.vue +++ b/frontend/src/components/Transactions/TransactionSend.vue @@ -19,10 +19,10 @@ - + - + diff --git a/frontend/src/components/UserCard.vue b/frontend/src/components/UserCard.vue index 728883109..beca89532 100755 --- a/frontend/src/components/UserCard.vue +++ b/frontend/src/components/UserCard.vue @@ -15,18 +15,18 @@
{{ $n(balance, 'decimal') }}
-
GDD
+
{{ $t('GDD') }}
{{ transactionCount }}
- {{ $t('transactions') }} + {{ $t('navigation.transactions') }}
-
--
+
{{ $t('em-dash') }}
{{ $t('community.community') }}
diff --git a/frontend/src/components/UserCard_FormUserMail.spec.js b/frontend/src/components/UserCard_FormUserMail.spec.js.old similarity index 95% rename from frontend/src/components/UserCard_FormUserMail.spec.js rename to frontend/src/components/UserCard_FormUserMail.spec.js.old index cc4911683..f59f610ee 100644 --- a/frontend/src/components/UserCard_FormUserMail.spec.js +++ b/frontend/src/components/UserCard_FormUserMail.spec.js.old @@ -42,8 +42,8 @@ describe('UserCard_FormUserMail', () => { expect(wrapper.find('a[href="#formusermail"]').exists()).toBeTruthy() }) - it('renders the E-Mail form.change', () => { - expect(wrapper.findAll('div.col').at(0).text()).toBe('E-Mail form.change') + it('renders the form.email form.change', () => { + expect(wrapper.findAll('div.col').at(0).text()).toBe('form.email form.change') }) it('renders the E-Mail', () => { diff --git a/frontend/src/components/UserCard_FormUserMail.vue b/frontend/src/components/UserCard_FormUserMail.vue.old similarity index 93% rename from frontend/src/components/UserCard_FormUserMail.vue rename to frontend/src/components/UserCard_FormUserMail.vue.old index e0d013973..8d7677c35 100644 --- a/frontend/src/components/UserCard_FormUserMail.vue +++ b/frontend/src/components/UserCard_FormUserMail.vue.old @@ -4,7 +4,7 @@ - E-Mail {{ $t('form.change') }} + {{ $t('form.email') }} {{ $t('form.change') }} diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index d4bf8c1da..5db319ad2 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -52,7 +52,9 @@ export const createUser = gql` lastName: $lastName language: $language publisherId: $publisherId - ) + ) { + id + } } ` @@ -69,3 +71,9 @@ export const createTransactionLink = gql` } } ` + +export const deleteTransactionLink = gql` + mutation($id: Float!) { + deleteTransactionLink(id: $id) + } +` diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 5af878756..5bf73fd9f 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -43,18 +43,8 @@ export const logout = gql` ` export const transactionsQuery = gql` - query( - $currentPage: Int = 1 - $pageSize: Int = 25 - $order: Order = DESC - $onlyCreations: Boolean = false - ) { - transactionList( - currentPage: $currentPage - pageSize: $pageSize - order: $order - onlyCreations: $onlyCreations - ) { + query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) { + transactionList(currentPage: $currentPage, pageSize: $pageSize, order: $order) { balanceGDT count linkCount @@ -149,3 +139,18 @@ export const queryTransactionLink = gql` } } ` + +export const listTransactionLinks = gql` + query($currentPage: Int = 1, $pageSize: Int = 5) { + listTransactionLinks(currentPage: $currentPage, pageSize: $pageSize) { + id + amount + holdAvailableAmount + memo + code + createdAt + validUntil + redeemedAt + } + } +` diff --git a/frontend/src/layouts/AuthLayout_gdd.vue b/frontend/src/layouts/AuthLayout_gdd.vue index 4d0f8cb78..e87ebe06a 100644 --- a/frontend/src/layouts/AuthLayout_gdd.vue +++ b/frontend/src/layouts/AuthLayout_gdd.vue @@ -8,7 +8,7 @@