Merge pull request #1327 from gradido/localize-datetime-admin

fix: Localize Datetime in Admin Interface
This commit is contained in:
Moriz Wahl 2022-02-02 15:26:12 +01:00 committed by GitHub
commit efadb6aa0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 399 additions and 636 deletions

View File

@ -448,7 +448,7 @@ jobs:
report_name: Coverage Admin Interface
type: lcov
result_path: ./coverage/lcov.info
min_coverage: 78
min_coverage: 81
token: ${{ github.token }}
##############################################################################

View File

@ -12,7 +12,7 @@
"dev": "yarn run serve",
"build": "vue-cli-service build",
"lint": "eslint --ext .js,.vue .",
"test": "jest --coverage",
"test": "TZ=UTC jest --coverage",
"locales": "scripts/missing-keys.sh && scripts/sort.sh"
},
"dependencies": {
@ -36,14 +36,12 @@
"graphql": "^15.6.1",
"identity-obj-proxy": "^3.0.0",
"jest": "26.6.3",
"moment": "^2.29.1",
"regenerator-runtime": "^0.13.9",
"stats-webpack-plugin": "^0.7.0",
"vue": "^2.6.11",
"vue-apollo": "^3.0.8",
"vue-i18n": "^8.26.5",
"vue-jest": "^3.0.7",
"vue-moment": "^4.1.0",
"vue-router": "^3.5.3",
"vue-toasted": "^1.1.28",
"vuex": "^3.6.2",

View File

@ -5,14 +5,6 @@ import { createPendingCreations } from '../graphql/createPendingCreations'
const localVue = global.localVue
const apolloMock = jest.fn().mockResolvedValue({
data: {
verifyLogin: {
name: 'success',
id: 0,
},
},
})
const apolloMutateMock = jest.fn().mockResolvedValue({
data: {
createPendingCreation: [0, 0, 0],
@ -23,19 +15,12 @@ const toastedErrorMock = jest.fn()
const toastedSuccessMock = jest.fn()
const mocks = {
$t: jest.fn((t) => t),
$moment: jest.fn(() => {
return {
format: jest.fn((m) => m),
subtract: jest.fn(() => {
return {
format: jest.fn((m) => m),
}
}),
}
$t: jest.fn((t, options) => (options ? [t, options] : t)),
$d: jest.fn((d) => {
const date = new Date(d)
return date.toISOString().split('T')[0]
}),
$apollo: {
query: apolloMock,
mutate: apolloMutateMock,
},
$store: {
@ -59,6 +44,12 @@ const propsData = {
itemsMassCreation: {},
}
const now = new Date(Date.now())
const getCreationDate = (sub) => {
const date = sub === 0 ? now : new Date(now.getFullYear(), now.getMonth() - sub, 1, 0)
return date.toISOString().split('T')[0]
}
describe('CreationFormular', () => {
let wrapper
@ -75,21 +66,24 @@ describe('CreationFormular', () => {
expect(wrapper.find('.component-creation-formular').exists()).toBeTruthy()
})
describe('server sends back moderator data', () => {
it('called store commit with mocked data', () => {
expect(stateCommitMock).toBeCalledWith('moderator', { name: 'success', id: 0 })
})
})
describe('server throws error for moderator data call', () => {
beforeEach(() => {
jest.clearAllMocks()
apolloMock.mockRejectedValueOnce({ message: 'Ouch!' })
wrapper = Wrapper()
describe('text and value form props', () => {
beforeEach(async () => {
wrapper = mount(CreationFormular, {
localVue,
mocks,
propsData: {
creationUserData: { memo: 'Memo from property', amount: 42 },
...propsData,
},
})
})
it('has called store commit with fake data', () => {
expect(stateCommitMock).toBeCalledWith('moderator', { id: 0, name: 'Test Moderator' })
it('has text taken from props', () => {
expect(wrapper.vm.text).toBe('Memo from property')
})
it('has value taken from props', () => {
expect(wrapper.vm.value).toBe(42)
})
})
@ -98,52 +92,6 @@ describe('CreationFormular', () => {
expect(wrapper.findAll('input[type="radio"]').length).toBe(3)
})
describe('with mass creation', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'massCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Test create coins' })
await wrapper.setData({ value: 90 })
})
describe('first radio button', () => {
beforeEach(async () => {
await wrapper.findAll('input[type="radio"]').at(0).setChecked()
})
it('emits update-radio-selected with index 0', () => {
expect(wrapper.emitted()['update-radio-selected']).toEqual([
[expect.arrayContaining([0])],
])
})
})
describe('second radio button', () => {
beforeEach(async () => {
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
})
it('emits update-radio-selected with index 1', () => {
expect(wrapper.emitted()['update-radio-selected']).toEqual([
[expect.arrayContaining([1])],
])
})
})
describe('third radio button', () => {
beforeEach(async () => {
await wrapper.findAll('input[type="radio"]').at(2).setChecked()
})
it('emits update-radio-selected with index 2', () => {
expect(wrapper.emitted()['update-radio-selected']).toEqual([
[expect.arrayContaining([2])],
])
})
})
})
describe('with single creation', () => {
beforeEach(async () => {
jest.clearAllMocks()
@ -153,17 +101,17 @@ describe('CreationFormular', () => {
item: { email: 'benjamin@bluemchen.de' },
})
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
await wrapper.find('textarea').setValue('Test create coins')
await wrapper.find('input[type="number"]').setValue(90)
})
describe('first radio button', () => {
beforeEach(async () => {
await wrapper.findAll('input[type="radio"]').at(0).setChecked()
await wrapper.find('textarea').setValue('Test create coins')
})
it('sets rangeMax to 200', () => {
expect(wrapper.vm.rangeMax).toBe(400)
expect(wrapper.vm.rangeMax).toBe(200)
})
describe('sendForm', () => {
@ -177,7 +125,7 @@ describe('CreationFormular', () => {
mutation: createPendingCreation,
variables: {
email: 'benjamin@bluemchen.de',
creationDate: 'YYYY-MM-01',
creationDate: getCreationDate(2),
amount: 90,
memo: 'Test create coins',
moderator: 0,
@ -185,9 +133,30 @@ describe('CreationFormular', () => {
}),
)
})
it('emits update-user-data', () => {
expect(wrapper.emitted('update-user-data')).toEqual([
[{ email: 'benjamin@bluemchen.de' }, [0, 0, 0]],
])
})
it('toasts a success message', () => {
expect(toastedSuccessMock).toBeCalledWith([
'creation_form.toasted',
{ email: 'benjamin@bluemchen.de', value: '90' },
])
})
it('updates open creations in store', () => {
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 1)
})
it('resets the form data', () => {
expect(wrapper.vm.value).toBe(0)
})
})
describe('sendForm', () => {
describe('sendForm with server error', () => {
beforeEach(async () => {
apolloMutateMock.mockRejectedValueOnce({ message: 'Ouch!' })
await wrapper.find('.test-submit').trigger('click')
@ -373,9 +342,18 @@ describe('CreationFormular', () => {
})
})
describe('with mass creation', () => {
describe('mass creation with success', () => {
beforeEach(async () => {
jest.clearAllMocks()
apolloMutateMock.mockResolvedValue({
data: {
createPendingCreations: {
success: true,
successfulCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'],
failedCreation: [],
},
},
})
await wrapper.setProps({
type: 'massCreation',
creation: [200, 400, 600],
@ -395,14 +373,14 @@ describe('CreationFormular', () => {
pendingCreations: [
{
email: 'bob@baumeister.de',
creationDate: 'YYYY-MM-01',
creationDate: getCreationDate(1),
amount: 200,
memo: 'Test mass create coins',
moderator: 0,
},
{
email: 'bibi@bloxberg.de',
creationDate: 'YYYY-MM-01',
creationDate: getCreationDate(1),
amount: 200,
memo: 'Test mass create coins',
moderator: 0,
@ -412,6 +390,73 @@ describe('CreationFormular', () => {
}),
)
})
it('updates open creations in store', () => {
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 2)
})
it('emits remove-all-bookmark', () => {
expect(wrapper.emitted('remove-all-bookmark')).toBeTruthy()
})
})
describe('mass creation with success but all failed', () => {
beforeEach(async () => {
jest.clearAllMocks()
apolloMutateMock.mockResolvedValue({
data: {
createPendingCreations: {
success: true,
successfulCreation: [],
failedCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'],
},
},
})
await wrapper.setProps({
type: 'massCreation',
creation: [200, 400, 600],
items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }],
})
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
await wrapper.find('textarea').setValue('Test mass create coins')
await wrapper.find('input[type="number"]').setValue(200)
await wrapper.find('.test-submit').trigger('click')
})
it('updates open creations in store', () => {
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 0)
})
it('toasts two errors', () => {
expect(toastedErrorMock).toBeCalledWith(
'Could not created PendingCreation for bob@baumeister.de',
)
expect(toastedErrorMock).toBeCalledWith(
'Could not created PendingCreation for bibi@bloxberg.de',
)
})
})
describe('mass creation with error', () => {
beforeEach(async () => {
jest.clearAllMocks()
apolloMutateMock.mockRejectedValue({
message: 'Oh no!',
})
await wrapper.setProps({
type: 'massCreation',
creation: [200, 400, 600],
items: [{ email: 'bob@baumeister.de' }, { email: 'bibi@bloxberg.de' }],
})
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
await wrapper.find('textarea').setValue('Test mass create coins')
await wrapper.find('input[type="number"]').setValue(200)
await wrapper.find('.test-submit').trigger('click')
})
it('toasts an error message', () => {
expect(toastedErrorMock).toBeCalledWith('Oh no!')
})
})
})
})

View File

@ -7,51 +7,15 @@
<label>{{ $t('creation_form.select_month') }}</label>
</div>
<b-row class="ml-4">
<b-col>
<b-form-radio
id="beforeLastMonth"
v-model="radioSelected"
:value="beforeLastMonth"
:disabled="creation[0] === 0"
size="lg"
@change="updateRadioSelected(beforeLastMonth, 0, creation[0])"
>
<label for="beforeLastMonth">
{{ beforeLastMonth.short }} {{ creation[0] != null ? creation[0] + ' GDD' : '' }}
</label>
</b-form-radio>
</b-col>
<b-col>
<b-form-radio
id="lastMonth"
v-model="radioSelected"
:value="lastMonth"
:disabled="creation[1] === 0"
size="lg"
@change="updateRadioSelected(lastMonth, 1, creation[1])"
>
<label for="lastMonth">
{{ lastMonth.short }} {{ creation[1] != null ? creation[1] + ' GDD' : '' }}
</label>
</b-form-radio>
</b-col>
<b-col>
<b-form-radio
id="currentMonth"
v-model="radioSelected"
:value="currentMonth"
:disabled="creation[2] === 0"
size="lg"
@change="updateRadioSelected(currentMonth, 2, creation[2])"
>
<label for="currentMonth">
{{ currentMonth.short }} {{ creation[2] != null ? creation[2] + ' GDD' : '' }}
</label>
</b-form-radio>
</b-col>
<b-form-radio-group
v-model="selected"
:options="radioOptions"
value-field="item"
text-field="name"
name="month-selection"
></b-form-radio-group>
</b-row>
<div class="m-4" v-show="createdIndex != null">
<b-row class="m-4" v-show="selected !== ''">
<label>{{ $t('creation_form.select_value') }}</label>
<div>
<b-input-group prepend="GDD" append=".00">
@ -62,7 +26,6 @@
:max="rangeMax"
></b-form-input>
</b-input-group>
<b-input-group prepend="0" :append="String(rangeMax)" class="mt-3">
<b-form-input
type="range"
@ -73,7 +36,7 @@
></b-form-input>
</b-input-group>
</div>
</div>
</b-row>
<div class="m-4">
<label>{{ $t('creation_form.enter_text') }}</label>
<div>
@ -100,18 +63,17 @@
variant="success"
class="test-submit"
@click="submitCreation"
:disabled="radioSelected === '' || value <= 0 || text.length < 10"
:disabled="selected === '' || value <= 0 || text.length < 10"
>
{{ $t('creation_form.update_creation') }}
</b-button>
<b-button
v-else
type="button"
variant="success"
class="test-submit"
@click="submitCreation"
:disabled="radioSelected === '' || value <= 0 || text.length < 10"
:disabled="selected === '' || value <= 0 || text.length < 10"
>
{{ $t('creation_form.submit_creation') }}
</b-button>
@ -123,11 +85,12 @@
</div>
</template>
<script>
import { verifyLogin } from '../graphql/verifyLogin'
import { createPendingCreation } from '../graphql/createPendingCreation'
import { createPendingCreations } from '../graphql/createPendingCreations'
import { creationMonths } from '../mixins/creationMonths'
export default {
name: 'CreationFormular',
mixins: [creationMonths],
props: {
type: {
type: String,
@ -166,71 +129,39 @@ export default {
},
data() {
return {
radioSelected: '',
text: !this.creationUserData.memo ? '' : this.creationUserData.memo,
value: !this.creationUserData.amount ? 0 : this.creationUserData.amount,
rangeMin: 0,
rangeMax: 1000,
currentMonth: {
short: this.$moment().format('MMMM'),
long: this.$moment().format('YYYY-MM-DD'),
year: this.$moment().format('YYYY'),
},
lastMonth: {
short: this.$moment().subtract(1, 'month').format('MMMM'),
long: this.$moment().subtract(1, 'month').format('YYYY-MM') + '-01',
year: this.$moment().subtract(1, 'month').format('YYYY'),
},
beforeLastMonth: {
short: this.$moment().subtract(2, 'month').format('MMMM'),
long: this.$moment().subtract(2, 'month').format('YYYY-MM') + '-01',
year: this.$moment().subtract(2, 'month').format('YYYY'),
},
submitObj: null,
isdisabled: true,
createdIndex: null,
selected: '',
}
},
methods: {
// Auswählen eines Zeitraumes
updateRadioSelected(name, index, openCreation) {
this.createdIndex = index
updateRadioSelected(name) {
// do we want to reset the memo everytime the month changes?
this.text = this.$t('creation_form.creation_for') + ' ' + name.short + ' ' + name.year
// Wenn Mehrfachschöpfung
if (this.type === 'massCreation') {
// An Creation.vue emitten und radioSelectedMass aktualisieren
this.$emit('update-radio-selected', [name, index])
} else if (this.type === 'singleCreation') {
if (this.type === 'singleCreation') {
this.rangeMin = 0
// Der maximale offene Betrag an GDD die für ein User noch geschöpft werden kann
this.rangeMax = openCreation
this.rangeMax = name.creation
}
},
submitCreation() {
let submitObj = []
if (this.type === 'massCreation') {
// Die anzahl der Mitglieder aus der Mehrfachschöpfung
const i = Object.keys(this.items).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 = []
this.items.forEach((item) => {
this.submitObj.push({
submitObj.push({
email: item.email,
creationDate: this.radioSelected.long,
creationDate: this.selected.date,
amount: Number(this.value),
memo: this.text,
moderator: Number(this.$store.state.moderator.id),
})
})
// eslint-disable-next-line no-console
console.log('MehrfachSCHÖPFUNG ABSENDEN FÜR >> ' + i + ' Mitglieder')
this.$apollo
.mutate({
mutation: createPendingCreations,
variables: {
pendingCreations: this.submitObj,
pendingCreations: submitObj,
},
fetchPolicy: 'no-cache',
})
@ -241,6 +172,7 @@ export default {
)
if (result.data.createPendingCreations.failedCreation.length > 0) {
result.data.createPendingCreations.failedCreation.forEach((failed) => {
// TODO: Please localize this error message
this.$toasted.error('Could not created PendingCreation for ' + failed)
})
}
@ -250,18 +182,17 @@ export default {
this.$toasted.error(error.message)
})
} else if (this.type === 'singleCreation') {
this.submitObj = {
submitObj = {
email: this.item.email,
creationDate: this.radioSelected.long,
creationDate: this.selected.date,
amount: Number(this.value),
memo: this.text,
moderator: Number(this.$store.state.moderator.id),
}
this.$apollo
.mutate({
mutation: createPendingCreation,
variables: this.submitObj,
variables: submitObj,
})
.then((result) => {
this.$emit('update-user-data', this.item, result.data.createPendingCreation)
@ -272,36 +203,22 @@ export default {
}),
)
this.$store.commit('openCreationsPlus', 1)
this.submitObj = null
this.createdIndex = null
// das creation Formular reseten
// what is this? Tests says that this.text is not reseted
this.$refs.creationForm.reset()
// Den geschöpften Wert auf o setzen
this.value = 0
})
.catch((error) => {
this.$toasted.error(error.message)
this.submitObj = null
// das creation Formular reseten
this.$refs.creationForm.reset()
// Den geschöpften Wert auf o setzen
this.value = 0
})
}
},
searchModeratorData() {
this.$apollo
.query({ query: verifyLogin })
.then((result) => {
this.$store.commit('moderator', result.data.verifyLogin)
})
.catch(() => {
this.$store.commit('moderator', { id: 0, name: 'Test Moderator' })
})
},
},
created() {
this.searchModeratorData()
watch: {
selected() {
this.updateRadioSelected(this.selected)
},
},
}
</script>

View File

@ -7,8 +7,9 @@ const apolloMutateMock = jest.fn().mockResolvedValue({
data: {
updatePendingCreation: {
creation: [0, 0, 0],
amount: 500,
date: new Date(),
memo: 'qwertzuiopasdfghjkl',
memo: 'Test Schöpfung 2',
moderator: 0,
},
},
@ -20,15 +21,9 @@ const toastedSuccessMock = jest.fn()
const mocks = {
$t: jest.fn((t) => t),
$moment: jest.fn(() => {
return {
format: jest.fn((m) => m),
subtract: jest.fn(() => {
return {
format: jest.fn((m) => m),
}
}),
}
$d: jest.fn((d) => {
const date = new Date(d)
return date.toISOString().split('T')[0]
}),
$apollo: {
mutate: apolloMutateMock,
@ -48,12 +43,18 @@ const mocks = {
},
}
const now = new Date(Date.now())
const getCreationDate = (sub) => {
const date = sub === 0 ? now : new Date(now.getFullYear(), now.getMonth() - sub, 1, 0)
return date.toISOString().split('T')[0]
}
const propsData = {
creation: [200, 400, 600],
creationUserData: {
memo: 'Test schöpfung 1',
amount: 100,
date: '2021-12-01',
date: getCreationDate(0),
},
item: {
id: 0,
@ -82,196 +83,79 @@ describe('EditCreationFormular', () => {
expect(wrapper.findAll('input[type="radio"]').length).toBe(3)
})
describe('with single creation', () => {
it('has the third radio button checked', () => {
expect(wrapper.findAll('input[type="radio"]').at(0).element.checked).toBeFalsy()
expect(wrapper.findAll('input[type="radio"]').at(1).element.checked).toBeFalsy()
expect(wrapper.findAll('input[type="radio"]').at(2).element.checked).toBeTruthy()
})
it('has rangeMax of 700', () => {
expect(wrapper.find('input[type="number"]').attributes('max')).toBe('700')
})
describe('change and save memo and value with success', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Test create coins' })
await wrapper.setData({ value: 90 })
await wrapper.find('input[type="number"]').setValue(500)
await wrapper.find('textarea').setValue('Test Schöpfung 2')
await wrapper.find('.test-submit').trigger('click')
})
describe('first radio button', () => {
beforeEach(async () => {
await wrapper.findAll('input[type="radio"]').at(0).setChecked()
})
it('sets rangeMin to 0', () => {
expect(wrapper.vm.rangeMin).toBe(0)
})
it('sets rangeMax to 200', () => {
expect(wrapper.vm.rangeMax).toBe(200)
})
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
amount: 90,
creationDate: 'YYYY-MM-01',
email: 'bob@baumeister.de',
id: 0,
memo: 'Test create coins',
moderator: 0,
},
}),
)
})
it('emits update-user-data', () => {
expect(wrapper.emitted('update-user-data')).toBeTruthy()
expect(wrapper.emitted('update-user-data')).toEqual([
[
{
id: 0,
email: 'bob@baumeister.de',
},
[0, 0, 0],
],
])
})
it('toast success message', () => {
expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_update')
})
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!')
})
})
})
it('calls the API', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
id: 0,
email: 'bob@baumeister.de',
creationDate: getCreationDate(0),
amount: 500,
memo: 'Test Schöpfung 2',
moderator: 0,
},
}),
)
})
describe('second radio button', () => {
beforeEach(async () => {
await wrapper.findAll('input[type="radio"]').at(1).setChecked()
})
it('sets rangeMin to 0', () => {
expect(wrapper.vm.rangeMin).toBe(0)
})
it('sets rangeMax to 400', () => {
expect(wrapper.vm.rangeMax).toBe(400)
})
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
amount: 90,
creationDate: 'YYYY-MM-01',
email: 'bob@baumeister.de',
id: 0,
memo: 'Test create coins',
moderator: 0,
},
}),
)
})
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!')
})
})
})
it('emits update-user-data', () => {
expect(wrapper.emitted('update-user-data')).toEqual([
[
{
id: 0,
email: 'bob@baumeister.de',
},
[0, 0, 0],
],
])
})
describe('third radio button', () => {
beforeEach(async () => {
await wrapper.setData({ rangeMin: 180 })
await wrapper.findAll('input[type="radio"]').at(2).setChecked()
})
it('emits update-creation-data', () => {
expect(wrapper.emitted('update-creation-data')).toEqual([
[
{
amount: 500,
date: expect.any(Date),
memo: 'Test Schöpfung 2',
moderator: 0,
row: expect.any(Object),
},
],
])
})
it('sets rangeMin to 180', () => {
expect(wrapper.vm.rangeMin).toBe(180)
})
it('toasts a success message', () => {
expect(toastedSuccessMock).toBeCalledWith('creation_form.toasted_update')
})
})
it('sets rangeMax to 700', () => {
expect(wrapper.vm.rangeMax).toBe(700)
})
describe('change and save memo and value with error', () => {
beforeEach(async () => {
apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
await wrapper.find('input[type="number"]').setValue(500)
await wrapper.find('textarea').setValue('Test Schöpfung 2')
await wrapper.find('.test-submit').trigger('click')
})
describe('sendForm with success', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
amount: 90,
creationDate: 'YYYY-MM-DD',
email: 'bob@baumeister.de',
id: 0,
memo: 'Test create coins',
moderator: 0,
},
}),
)
})
})
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!')
})
})
it('toasts an error message', () => {
expect(toastedErrorMock).toBeCalledWith('Oh no!')
})
})
})

View File

@ -6,65 +6,14 @@
<label>{{ $t('creation_form.select_month') }}</label>
</div>
<b-row class="m-4">
<b-col class="text-left">
<b-form-radio
id="beforeLastMonth"
v-model="radioSelected"
:value="beforeLastMonth"
:disabled="selectedOpenCreationAmount[0] === 0"
size="lg"
@change="updateRadioSelected(beforeLastMonth, 0, selectedOpenCreationAmount[0])"
>
<label for="beforeLastMonth">
{{ beforeLastMonth.short }}
{{
selectedOpenCreationAmount[0] != null
? selectedOpenCreationAmount[0] + ' GDD'
: ''
}}
</label>
</b-form-radio>
</b-col>
<b-col>
<b-form-radio
id="lastMonth"
v-model="radioSelected"
:value="lastMonth"
:disabled="selectedOpenCreationAmount[1] === 0"
size="lg"
@change="updateRadioSelected(lastMonth, 1, selectedOpenCreationAmount[1])"
>
<label for="lastMonth">
{{ lastMonth.short }}
{{
selectedOpenCreationAmount[1] != null
? selectedOpenCreationAmount[1] + ' GDD'
: ''
}}
</label>
</b-form-radio>
</b-col>
<b-col class="text-right">
<b-form-radio
id="currentMonth"
v-model="radioSelected"
:value="currentMonth"
:disabled="selectedOpenCreationAmount[2] === 0"
size="lg"
@change="updateRadioSelected(currentMonth, 2, selectedOpenCreationAmount[2])"
>
<label for="currentMonth">
{{ currentMonth.short }}
{{
selectedOpenCreationAmount[2] != null
? selectedOpenCreationAmount[2] + ' GDD'
: ''
}}
</label>
</b-form-radio>
</b-col>
<b-form-radio-group
v-model="selected"
:options="radioOptions"
value-field="item"
text-field="name"
name="month-selection"
></b-form-radio-group>
</b-row>
<div class="m-4">
<label>{{ $t('creation_form.select_value') }}</label>
<div>
@ -76,7 +25,6 @@
:max="rangeMax"
></b-form-input>
</b-input-group>
<b-input-group prepend="0" :append="String(rangeMax)" class="mt-3">
<b-form-input
type="range"
@ -113,7 +61,7 @@
variant="success"
class="test-submit"
@click="submitCreation"
:disabled="radioSelected === '' || value <= 0 || text.length < 10"
:disabled="selected === '' || value <= 0 || text.length < 10"
>
{{ $t('creation_form.update_creation') }}
</b-button>
@ -126,8 +74,11 @@
</template>
<script>
import { updatePendingCreation } from '../graphql/updatePendingCreation'
import { creationMonths } from '../mixins/creationMonths'
export default {
name: 'EditCreationFormular',
mixins: [creationMonths],
props: {
item: {
type: Object,
@ -151,51 +102,26 @@ export default {
},
data() {
return {
radioSelected: '',
text: !this.creationUserData.memo ? '' : this.creationUserData.memo,
value: !this.creationUserData.amount ? 0 : this.creationUserData.amount,
rangeMin: 0,
rangeMax: 1000,
currentMonth: {
short: this.$moment().format('MMMM'),
long: this.$moment().format('YYYY-MM-DD'),
},
lastMonth: {
short: this.$moment().subtract(1, 'month').format('MMMM'),
long: this.$moment().subtract(1, 'month').format('YYYY-MM') + '-01',
},
beforeLastMonth: {
short: this.$moment().subtract(2, 'month').format('MMMM'),
long: this.$moment().subtract(2, 'month').format('YYYY-MM') + '-01',
},
submitObj: null,
isdisabled: true,
createdIndex: null,
selectedOpenCreationAmount: {},
selected: '',
}
},
methods: {
updateRadioSelected(name, index, openCreation) {
this.createdIndex = index
this.rangeMin = 0
this.rangeMax = this.creation[index]
},
submitCreation() {
this.submitObj = {
id: this.item.id,
email: this.item.email,
creationDate: this.radioSelected.long,
amount: Number(this.value),
memo: this.text,
moderator: Number(this.$store.state.moderator.id),
}
// hinweis das eine ein einzelne Schöpfung abgesendet wird an (email)
this.$apollo
.mutate({
mutation: updatePendingCreation,
variables: this.submitObj,
variables: {
id: this.item.id,
email: this.item.email,
creationDate: this.selected.date,
amount: Number(this.value),
memo: this.text,
moderator: Number(this.$store.state.moderator.id),
},
})
.then((result) => {
this.$emit('update-user-data', this.item, result.data.updatePendingCreation.creation)
@ -212,8 +138,6 @@ export default {
email: this.item.email,
}),
)
this.submitObj = null
this.createdIndex = null
// das creation Formular reseten
this.$refs.updateCreationForm.reset()
// Den geschöpften Wert auf o setzen
@ -221,7 +145,6 @@ export default {
})
.catch((error) => {
this.$toasted.error(error.message)
this.submitObj = null
// das creation Formular reseten
this.$refs.updateCreationForm.reset()
// Den geschöpften Wert auf o setzen
@ -231,25 +154,10 @@ export default {
},
created() {
if (this.creationUserData.date) {
switch (this.$moment(this.creationUserData.date).format('MMMM')) {
case this.currentMonth.short:
this.createdIndex = 2
this.radioSelected = this.currentMonth
break
case this.lastMonth.short:
this.createdIndex = 1
this.radioSelected = this.lastMonth
break
case this.beforeLastMonth.short:
this.createdIndex = 0
this.radioSelected = this.beforeLastMonth
break
default:
throw new Error('Something went wrong')
}
this.selectedOpenCreationAmount[this.createdIndex] =
this.creation[this.createdIndex] + this.creationUserData.amount
this.rangeMax = this.selectedOpenCreationAmount[this.createdIndex]
const month = this.$d(new Date(this.creationUserData.date), 'month')
const index = this.radioOptions.findIndex((obj) => obj.item.short === month)
this.selected = this.radioOptions[index].item
this.rangeMax = this.creation[index] + this.creationUserData.amount
}
},
}

View File

@ -107,16 +107,7 @@ describe('UserTable', () => {
const mocks = {
$t: jest.fn((t) => t),
$moment: jest.fn(() => {
return {
format: jest.fn((m) => m),
subtract: jest.fn(() => {
return {
format: jest.fn((m) => m),
}
}),
}
}),
$d: jest.fn((d) => d),
$apollo: {
query: apolloQueryMock,
},

View File

@ -116,7 +116,7 @@
<confirm-register-mail-formular
:checked="row.item.emailChecked"
:email="row.item.email"
:dateLastSend="$moment().subtract(1, 'month').format('dddd, DD.MMMM.YYYY HH:mm'),"
:dateLastSend="$d(new Date(), 'long')"
/>
</template>
<template #show-transaction-list>

View File

@ -60,6 +60,15 @@ const dateTimeFormats = {
hour: 'numeric',
minute: 'numeric',
},
monthShort: {
month: 'short',
},
month: {
month: 'long',
},
year: {
year: 'numeric',
},
},
de: {
short: {
@ -75,6 +84,15 @@ const dateTimeFormats = {
hour: 'numeric',
minute: 'numeric',
},
monthShort: {
month: 'short',
},
month: {
month: 'long',
},
year: {
year: 'numeric',
},
},
}

View File

@ -18,6 +18,7 @@
"toasted_update": "`Offene Schöpfung {value} GDD) für {email} wurde geändert und liegt zur Bestätigung bereit",
"update_creation": "Schöpfung aktualisieren"
},
"date": "Datum",
"details": "Details",
"e_mail": "E-Mail",
"firstname": "Vorname",

View File

@ -18,6 +18,7 @@
"toasted_update": "Open creation {value} GDD) for {email} has been changed and is ready for confirmation.",
"update_creation": "Creation update"
},
"date": "Date",
"details": "Details",
"e_mail": "E-mail",
"firstname": "Firstname",

View File

@ -17,7 +17,6 @@ import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import moment from 'vue-moment'
import Toasted from 'vue-toasted'
import { apolloProvider } from './plugins/apolloProvider'
@ -26,8 +25,6 @@ Vue.use(BootstrapVue)
Vue.use(IconsPlugin)
Vue.use(moment)
Vue.use(VueApollo)
Vue.use(Toasted, {
@ -48,7 +45,6 @@ i18n.locale =
store.state.moderator && store.state.moderator.language ? store.state.moderator.language : 'en'
new Vue({
moment,
router,
store,
i18n,

View File

@ -6,7 +6,6 @@ import Vue from 'vue'
import VueApollo from 'vue-apollo'
import i18n from './i18n'
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
import moment from 'vue-moment'
import store from './store/store'
import router from './router/router'
@ -14,7 +13,6 @@ jest.mock('vue')
jest.mock('vue-apollo')
jest.mock('vuex')
jest.mock('vue-i18n')
jest.mock('vue-moment')
jest.mock('./store/store', () => {
return {
state: {
@ -90,10 +88,6 @@ describe('main', () => {
expect(Vue.use).toBeCalledWith(IconsPlugin)
})
it('calls Moment', () => {
expect(Vue.use).toBeCalledWith(moment)
})
it('creates a store', () => {
expect(Vue).toBeCalledWith(
expect.objectContaining({

View File

@ -0,0 +1,35 @@
export const creationMonths = {
props: {
creation: [1000, 1000, 1000],
},
computed: {
creationDates() {
const now = new Date(Date.now())
const dates = [now]
for (let i = 1; i < 3; i++) {
dates.push(new Date(now.getFullYear(), now.getMonth() - i, 1))
}
return dates.reverse()
},
creationDateObjects() {
const result = []
this.creationDates.forEach((date) => {
result.push({
short: this.$d(date, 'month'),
long: this.$d(date, 'short'),
year: this.$d(date, 'year'),
date: this.$d(date, 'short', 'en'),
})
})
return result
},
radioOptions() {
return this.creationDateObjects.map((obj, idx) => {
return {
item: { ...obj, creation: this.creation[idx] },
name: obj.short + (this.creation[idx] ? ' ' + this.creation[idx] + ' GDD' : ''),
}
})
},
},
}

View File

@ -32,22 +32,13 @@ const toastErrorMock = jest.fn()
const mocks = {
$t: jest.fn((t) => t),
$d: jest.fn((d) => d),
$apollo: {
query: apolloQueryMock,
},
$toasted: {
error: toastErrorMock,
},
$moment: jest.fn(() => {
return {
format: jest.fn((m) => m),
subtract: jest.fn(() => {
return {
format: jest.fn((m) => m),
}
}),
}
}),
}
describe('Creation', () => {

View File

@ -65,44 +65,6 @@ export default {
data() {
return {
showArrays: false,
Searchfields: [
{ key: 'bookmark', label: 'bookmark' },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'creation',
// label: this.$t('open_creation') + 'Jan | Feb | März',
label:
this.$moment().subtract(2, 'month').format('MMM') +
' | ' +
this.$moment().subtract(1, 'month').format('MMM') +
' | ' +
this.$moment().format('MMM'),
formatter: (value, key, item) => {
return String(value[0]) + ` | ` + String(value[1]) + ` | ` + String(value[2])
},
},
{ key: 'email', label: this.$t('e_mail') },
],
fields: [
{ key: 'email', label: this.$t('e_mail') },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'creation',
// label: this.$t('open_creation') + 'Jan | Feb | März',
label:
this.$moment().subtract(2, 'month').format('MMM') +
' | ' +
this.$moment().subtract(1, 'month').format('MMM') +
' | ' +
this.$moment().format('MMM'),
formatter: (value, key, item) => {
return String(value[0]) + ` | ` + String(value[1]) + ` | ` + String(value[2])
},
},
{ key: 'bookmark', label: this.$t('remove') },
],
itemsList: [],
itemsMassCreation: [],
radioSelectedMass: '',
@ -111,6 +73,7 @@ export default {
rows: 0,
currentPage: 1,
perPage: 25,
now: Date.now(),
}
},
async created() {
@ -167,6 +130,48 @@ export default {
this.getUsers()
},
},
computed: {
Searchfields() {
return [
{ key: 'bookmark', label: 'bookmark' },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'creation',
label: this.creationLabel,
formatter: (value, key, item) => {
return value.join(' | ')
},
},
{ key: 'email', label: this.$t('e_mail') },
]
},
fields() {
return [
{ key: 'email', label: this.$t('e_mail') },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'creation',
label: this.creationLabel,
formatter: (value, key, item) => {
return value.join(' | ')
},
},
{ key: 'bookmark', label: this.$t('remove') },
]
},
creationLabel() {
const now = new Date(this.now)
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1)
const beforeLastMonth = new Date(now.getFullYear(), now.getMonth() - 2, 1)
return [
this.$d(beforeLastMonth, 'monthShort'),
this.$d(lastMonth, 'monthShort'),
this.$d(now, 'monthShort'),
].join(' | ')
},
},
watch: {
currentPage() {
this.getUsers()

View File

@ -39,6 +39,7 @@ const apolloMutateMock = jest.fn().mockResolvedValue({})
const mocks = {
$t: jest.fn((t) => t),
$d: jest.fn((d) => d),
$store: {
commit: storeCommitMock,
},
@ -50,11 +51,6 @@ const mocks = {
error: toastedErrorMock,
success: toastedSuccessMock,
},
$moment: jest.fn((value) => {
return {
format: jest.fn((format) => value),
}
}),
}
describe('CreationConfirm', () => {

View File

@ -96,9 +96,9 @@ export default {
{ key: 'memo', label: 'Text' },
{
key: 'date',
label: 'Datum',
label: this.$t('date'),
formatter: (value) => {
return this.$moment(value).format('ll')
return this.$d(new Date(value), 'short')
},
},
{ key: 'moderator', label: 'Moderator' },

View File

@ -24,22 +24,13 @@ const toastErrorMock = jest.fn()
const mocks = {
$t: jest.fn((t) => t),
$d: jest.fn((d) => d),
$apollo: {
query: apolloQueryMock,
},
$toasted: {
error: toastErrorMock,
},
$moment: jest.fn(() => {
return {
format: jest.fn((m) => m),
subtract: jest.fn(() => {
return {
format: jest.fn((m) => m),
}
}),
}
}),
}
describe('UserSearch', () => {

View File

@ -44,41 +44,14 @@ export default {
data() {
return {
showArrays: false,
fields: [
{ key: 'email', label: this.$t('e_mail') },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'creation',
label: [
this.$moment().subtract(2, 'month').format('MMM'),
this.$moment().subtract(1, 'month').format('MMM'),
this.$moment().format('MMM'),
].join(' | '),
formatter: (value, key, item) => {
return value.join(' | ')
},
},
{ key: 'show_details', label: this.$t('details') },
{ key: 'confirm_mail', label: this.$t('confirmed') },
{ key: 'transactions_list', label: this.$t('transaction') },
],
searchResult: [],
massCreation: [],
criteria: '',
currentMonth: {
short: this.$moment().format('MMMM'),
},
lastMonth: {
short: this.$moment().subtract(1, 'month').format('MMMM'),
},
beforeLastMonth: {
short: this.$moment().subtract(2, 'month').format('MMMM'),
},
filterCheckedEmails: false,
rows: 0,
currentPage: 1,
perPage: 25,
now: Date.now(),
}
},
methods: {
@ -111,6 +84,37 @@ export default {
this.getUsers()
},
},
computed: {
lastMonthDate() {
const now = new Date(this.now)
return new Date(now.getFullYear(), now.getMonth() - 1, 1)
},
beforeLastMonthDate() {
const now = new Date(this.now)
return new Date(now.getFullYear(), now.getMonth() - 2, 1)
},
fields() {
return [
{ key: 'email', label: this.$t('e_mail') },
{ key: 'firstName', label: this.$t('firstname') },
{ key: 'lastName', label: this.$t('lastname') },
{
key: 'creation',
label: [
this.$d(this.beforeLastMonthDate, 'monthShort'),
this.$d(this.lastMonthDate, 'monthShort'),
this.$d(this.now, 'monthShort'),
].join(' | '),
formatter: (value, key, item) => {
return value.join(' | ')
},
},
{ key: 'show_details', label: this.$t('details') },
{ key: 'confirm_mail', label: this.$t('confirmed') },
{ key: 'transactions_list', label: this.$t('transaction') },
]
},
},
created() {
this.getUsers()
},

View File

@ -9032,11 +9032,6 @@ mkdirp@0.x, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
moment@^2.19.2, moment@^2.29.1:
version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@ -12491,13 +12486,6 @@ vue-loader@^15.9.2:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"
vue-moment@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/vue-moment/-/vue-moment-4.1.0.tgz#092a8ff723a96c6f85a0a8e23ad30f0bf320f3b0"
integrity sha512-Gzisqpg82ItlrUyiD9d0Kfru+JorW2o4mQOH06lEDZNgxci0tv/fua1Hl0bo4DozDV2JK1r52Atn/8QVCu8qQw==
dependencies:
moment "^2.19.2"
vue-router@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.5.3.tgz#041048053e336829d05dafacf6a8fb669a2e7999"