diff --git a/admin/src/components/ConfirmRegisterMailFormular.spec.js b/admin/src/components/ConfirmRegisterMailFormular.spec.js new file mode 100644 index 000000000..8872128e9 --- /dev/null +++ b/admin/src/components/ConfirmRegisterMailFormular.spec.js @@ -0,0 +1,75 @@ +import { mount } from '@vue/test-utils' +import ConfirmRegisterMailFormular from './ConfirmRegisterMailFormular.vue' + +const localVue = global.localVue + +const apolloMutateMock = jest.fn().mockResolvedValue() +const toastSuccessMock = jest.fn() +const toastErrorMock = jest.fn() + +const mocks = { + $apollo: { + mutate: apolloMutateMock, + }, + $toasted: { + success: toastSuccessMock, + error: toastErrorMock, + }, +} + +const propsData = { + email: 'bob@baumeister.de', + dateLastSend: '', +} + +describe('ConfirmRegisterMailFormular', () => { + let wrapper + + const Wrapper = () => { + return mount(ConfirmRegisterMailFormular, { localVue, mocks, propsData }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a DIV element with the class.component-confirm-register-mail', () => { + expect(wrapper.find('.component-confirm-register-mail').exists()).toBeTruthy() + }) + + describe('send register mail with success', () => { + beforeEach(() => { + wrapper.find('button.test-button').trigger('click') + }) + + it('calls the API with email', () => { + expect(apolloMutateMock).toBeCalledWith( + expect.objectContaining({ + variables: { email: 'bob@baumeister.de' }, + }), + ) + }) + + it('toasts a success message', () => { + expect(toastSuccessMock).toBeCalledWith( + 'Erfolgreich senden der Confirmation Link an die E-Mail des Users! bob@baumeister.de', + ) + }) + }) + + describe('send register mail with error', () => { + beforeEach(() => { + apolloMutateMock.mockRejectedValue({ message: 'OUCH!' }) + wrapper = Wrapper() + wrapper.find('button.test-button').trigger('click') + }) + + it('toasts an error message', () => { + expect(toastErrorMock).toBeCalledWith( + 'Fehler beim senden des confirmation link an den Benutzer: OUCH!', + ) + }) + }) + }) +}) diff --git a/admin/src/components/ConfirmRegisterMailFormular.vue b/admin/src/components/ConfirmRegisterMailFormular.vue new file mode 100644 index 000000000..866e8a487 --- /dev/null +++ b/admin/src/components/ConfirmRegisterMailFormular.vue @@ -0,0 +1,62 @@ + + + + + Die letzte Email wurde am + {{ dateLastSend }} Uhr + an das Mitglied ({{ email }}) gesendet. + + + + + + + + Registrierungs-Email bestätigen, jetzt senden + + + + + + + + diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js index f6bd1a924..1c7dd40fc 100644 --- a/admin/src/components/CreationFormular.spec.js +++ b/admin/src/components/CreationFormular.spec.js @@ -176,8 +176,8 @@ describe('CreationFormular', () => { await wrapper.find('.test-submit').trigger('click') }) - it('sends ... to apollo', () => { - expect(toastedErrorMock).toBeCalled() + it('toasts an error message', () => { + expect(toastedErrorMock).toBeCalledWith('Ouch!') }) }) diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index d73ea3c81..efaff3481 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -1,5 +1,6 @@ + CREATION FORMULAR @@ -204,8 +205,6 @@ export default { // Die anzahl der Mitglieder aus der Mehrfachschöpfung const i = Object.keys(this.itemsMassCreation).length // hinweis das eine Mehrfachschöpfung ausgeführt wird an (Anzahl der MItgleider an die geschöpft wird) - // eslint-disable-next-line no-console - console.log('SUBMIT CREATION => ' + this.type + ' >> für VIELE ' + i + ' Mitglieder') this.submitObj = [ { item: this.itemsMassCreation, @@ -216,8 +215,6 @@ export default { moderator: this.$store.state.moderator.id, }, ] - // eslint-disable-next-line no-console - console.log('MehrfachSCHÖPFUNG ABSENDEN FÜR >> ' + i + ' Mitglieder') // $store - offene Schöpfungen hochzählen this.$store.commit('openCreationsPlus', i) diff --git a/admin/src/components/CreationTransactionListFormular.spec.js b/admin/src/components/CreationTransactionListFormular.spec.js new file mode 100644 index 000000000..80b337268 --- /dev/null +++ b/admin/src/components/CreationTransactionListFormular.spec.js @@ -0,0 +1,115 @@ +import { mount } from '@vue/test-utils' +import CreationTransactionListFormular from './CreationTransactionListFormular.vue' + +const localVue = global.localVue + +const apolloQueryMock = jest.fn().mockResolvedValue({ + data: { + transactionList: { + transactions: [ + { + type: 'created', + balance: 100, + decayStart: 0, + decayEnd: 0, + decayDuration: 0, + memo: 'Testing', + transactionId: 1, + name: 'Bibi', + email: 'bibi@bloxberg.de', + date: new Date(), + decay: { + balance: 0.01, + decayStart: 0, + decayEnd: 0, + decayDuration: 0, + decayStartBlock: 0, + }, + }, + { + type: 'created', + balance: 200, + decayStart: 0, + decayEnd: 0, + decayDuration: 0, + memo: 'Testing 2', + transactionId: 2, + name: 'Bibi', + email: 'bibi@bloxberg.de', + date: new Date(), + decay: { + balance: 0.01, + decayStart: 0, + decayEnd: 0, + decayDuration: 0, + decayStartBlock: 0, + }, + }, + ], + }, + }, +}) + +const toastedErrorMock = jest.fn() + +const mocks = { + $apollo: { + query: apolloQueryMock, + }, + $toasted: { + global: { + error: toastedErrorMock, + }, + }, +} + +const propsData = { + userId: 1, +} + +describe('CreationTransactionListFormular', () => { + let wrapper + + const Wrapper = () => { + return mount(CreationTransactionListFormular, { localVue, mocks, propsData }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('sends query to Apollo when created', () => { + expect(apolloQueryMock).toBeCalledWith( + expect.objectContaining({ + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + onlyCreations: true, + userId: 1, + }, + }), + ) + }) + + it('has two values for the transaction', () => { + expect(wrapper.find('tbody').findAll('tr').length).toBe(2) + }) + + describe('query transaction with error', () => { + beforeEach(() => { + apolloQueryMock.mockRejectedValue({ message: 'OUCH!' }) + wrapper = Wrapper() + }) + + it('calls the API', () => { + expect(apolloQueryMock).toBeCalled() + }) + + it('toast error', () => { + expect(toastedErrorMock).toBeCalledWith('OUCH!') + }) + }) + }) +}) diff --git a/admin/src/components/CreationTransactionListFormular.vue b/admin/src/components/CreationTransactionListFormular.vue new file mode 100644 index 000000000..04f1c9a13 --- /dev/null +++ b/admin/src/components/CreationTransactionListFormular.vue @@ -0,0 +1,44 @@ + + + Alle Geschöpften Transaktionen für den User + + + + diff --git a/admin/src/components/EditCreationFormular.spec.js b/admin/src/components/EditCreationFormular.spec.js index 50704ed76..b7b091e32 100644 --- a/admin/src/components/EditCreationFormular.spec.js +++ b/admin/src/components/EditCreationFormular.spec.js @@ -46,9 +46,12 @@ const mocks = { } const propsData = { - type: '', - creation: [], - itemsMassCreation: {}, + creation: [200, 400, 600], + creationUserData: { + memo: 'Test schöpfung 1', + amount: 100, + date: '2021-12-01', + }, } describe('EditCreationFormular', () => { @@ -67,7 +70,7 @@ describe('EditCreationFormular', () => { expect(wrapper.find('.component-edit-creation-formular').exists()).toBeTruthy() }) - describe('radio buttons to selcet month', () => { + describe('radio buttons to select month', () => { it('has three radio buttons', () => { expect(wrapper.findAll('input[type="radio"]').length).toBe(3) }) @@ -75,7 +78,7 @@ describe('EditCreationFormular', () => { describe('with single creation', () => { beforeEach(async () => { jest.clearAllMocks() - await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] }) + await wrapper.setProps({ creation: [200, 400, 600] }) await wrapper.setData({ rangeMin: 180 }) await wrapper.setData({ text: 'Test create coins' }) await wrapper.setData({ value: 90 }) @@ -113,6 +116,26 @@ describe('EditCreationFormular', () => { }), ) }) + + describe('sendForm with error', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutateMock.mockRejectedValue({ + message: 'Ouch!', + }) + wrapper = Wrapper() + await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] }) + await wrapper.setData({ text: 'Test create coins' }) + await wrapper.setData({ value: 90 }) + await wrapper.findAll('input[type="radio"]').at(0).setChecked() + await wrapper.setData({ rangeMin: 100 }) + await wrapper.find('.test-submit').trigger('click') + }) + + it('toast error message', () => { + expect(toastedErrorMock).toBeCalledWith('Ouch!') + }) + }) }) }) @@ -148,23 +171,44 @@ describe('EditCreationFormular', () => { }), ) }) + + describe('sendForm with error', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutateMock.mockRejectedValue({ + message: 'Ouch!', + }) + wrapper = Wrapper() + await wrapper.setProps({ creation: [200, 400, 600] }) + await wrapper.setData({ text: 'Test create coins' }) + await wrapper.setData({ value: 100 }) + await wrapper.findAll('input[type="radio"]').at(1).setChecked() + await wrapper.setData({ rangeMin: 180 }) + await wrapper.find('.test-submit').trigger('click') + }) + + it('toast error message', () => { + expect(toastedErrorMock).toBeCalledWith('Ouch!') + }) + }) }) }) describe('third radio button', () => { beforeEach(async () => { + await wrapper.setData({ rangeMin: 180 }) await wrapper.findAll('input[type="radio"]').at(2).setChecked() }) - it('sets rangeMin to 0', () => { - expect(wrapper.vm.rangeMin).toBe(0) + it('sets rangeMin to 180', () => { + expect(wrapper.vm.rangeMin).toBe(180) }) - it('sets rangeMax to 400', () => { - expect(wrapper.vm.rangeMax).toBe(600) + it('sets rangeMax to 700', () => { + expect(wrapper.vm.rangeMax).toBe(700) }) - describe('sendForm', () => { + describe('sendForm with success', () => { beforeEach(async () => { await wrapper.find('.test-submit').trigger('click') }) @@ -184,6 +228,26 @@ describe('EditCreationFormular', () => { ) }) }) + + describe('sendForm with error', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutateMock.mockRejectedValue({ + message: 'Ouch!', + }) + wrapper = Wrapper() + await wrapper.setProps({ creation: [200, 400, 600] }) + await wrapper.setData({ text: 'Test create coins' }) + await wrapper.setData({ value: 90 }) + await wrapper.findAll('input[type="radio"]').at(2).setChecked() + await wrapper.setData({ rangeMin: 180 }) + await wrapper.find('.test-submit').trigger('click') + }) + + it('toast error message', () => { + expect(toastedErrorMock).toBeCalledWith('Ouch!') + }) + }) }) }) }) diff --git a/admin/src/components/EditCreationFormular.vue b/admin/src/components/EditCreationFormular.vue index 3a1c91a02..84a155206 100644 --- a/admin/src/components/EditCreationFormular.vue +++ b/admin/src/components/EditCreationFormular.vue @@ -113,7 +113,7 @@ @click="submitCreation" :disabled="radioSelected === '' || value <= 0 || text.length < 10" > - Update Schöpfung ({{ type }},{{ pagetype }}) + Update Schöpfung @@ -127,15 +127,6 @@ import { updatePendingCreation } from '../graphql/updatePendingCreation' export default { name: 'EditCreationFormular', props: { - type: { - type: String, - required: false, - }, - pagetype: { - type: String, - required: false, - default: '', - }, item: { type: Object, required: false, @@ -143,13 +134,6 @@ export default { return {} }, }, - items: { - type: Array, - required: false, - default() { - return [] - }, - }, row: { type: Object, required: false, @@ -247,7 +231,7 @@ export default { }, }, created() { - if (this.pagetype === 'PageCreationConfirm' && this.creationUserData.date) { + if (this.creationUserData.date) { switch (this.$moment(this.creationUserData.date).format('MMMM')) { case this.currentMonth.short: this.createdIndex = 2 diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index aaff9d61d..24286f01c 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -1,6 +1,6 @@ - + @@ -9,19 +9,18 @@ - Übersicht | - Usersuche | + Übersicht + Usersuche Mehrfachschöpfung - | {{ $store.state.openCreations }} offene Schöpfungen + {{ $store.state.openCreations }} offene Schöpfungen Wallet Logout - @@ -49,4 +48,7 @@ export default { height: 2rem; padding-left: 10px; } +.bg-color-creation { + background-color: #cf1010dc; +} diff --git a/admin/src/components/RowDetails.vue b/admin/src/components/RowDetails.vue new file mode 100644 index 000000000..7153870ee --- /dev/null +++ b/admin/src/components/RowDetails.vue @@ -0,0 +1,27 @@ + + + + + + + + + Details verbergen von {{ row.item.firstName }} {{ row.item.lastName }} + + + + + diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue index 9a0e876b2..eae328adf 100644 --- a/admin/src/components/UserTable.vue +++ b/admin/src/components/UserTable.vue @@ -37,62 +37,81 @@ stacked="md" > - - - + + - - - + + + + + + + + + + + + + + - - - - - {{ type }} - - - - - - Details verbergen von {{ row.item.firstName }} {{ row.item.lastName }} - - + + + + + + + + + + + + + + - import CreationFormular from '../components/CreationFormular.vue' import EditCreationFormular from '../components/EditCreationFormular.vue' +import ConfirmRegisterMailFormular from '../components/ConfirmRegisterMailFormular.vue' +import CreationTransactionListFormular from '../components/CreationTransactionListFormular.vue' +import RowDetails from '../components/RowDetails.vue' + import { confirmPendingCreation } from '../graphql/confirmPendingCreation' +const slotNames = ['show-creation', 'show-register-mail', 'show-transaction-list'] + export default { name: 'UserTable', props: { @@ -162,9 +187,15 @@ export default { components: { CreationFormular, EditCreationFormular, + ConfirmRegisterMailFormular, + CreationTransactionListFormular, + RowDetails, }, data() { return { + showCreationFormular: null, + showConfirmRegisterMailFormular: null, + showCreationTransactionListFormular: null, creationUserData: {}, overlay: false, overlayBookmarkType: '', @@ -178,9 +209,35 @@ export default { button_cancel: 'Cancel', }, ], + slotIndex: 0, + openRow: null, } }, methods: { + rowToogleDetails(row, index) { + if (this.openRow) { + if (this.openRow.index === row.index) { + if (index === this.slotIndex) { + row.toggleDetails() + this.openRow = null + } else { + this.slotIndex = index + } + } else { + this.openRow.toggleDetails() + row.toggleDetails() + this.slotIndex = index + this.openRow = row + } + } else { + row.toggleDetails() + this.slotIndex = index + this.openRow = row + if (this.type === 'PageCreationConfirm') { + this.creationUserData = row.item + } + } + }, overlayShow(bookmarkType, item) { this.overlay = true this.overlayBookmarkType = bookmarkType @@ -243,14 +300,6 @@ export default { this.$toasted.error(error.message) }) }, - editCreationUserTable(row, rowItem) { - if (!row.detailsShowing) { - this.creationUserData = rowItem - } else { - this.creationUserData = {} - } - row.toggleDetails() - }, updateCreationData(data) { this.creationUserData.amount = data.amount this.creationUserData.date = data.date @@ -263,6 +312,11 @@ export default { rowItem.creation = newCreation }, }, + computed: { + slotName() { + return slotNames[this.slotIndex] + }, + }, }