mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch '531-Newsletter-subscribe-status-change-in-user-profile' into apollo-clicktipp-connector
This commit is contained in:
commit
123f45c853
@ -113,12 +113,6 @@ describe('SideBar', () => {
|
||||
expect(wrapper.emitted('logout')).toEqual([[]])
|
||||
})
|
||||
})
|
||||
|
||||
describe('language-switch', () => {
|
||||
it('has a language-switch button', () => {
|
||||
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -64,23 +64,18 @@
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="mt-5 ml-4">
|
||||
<language-switch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
import NavbarToggleButton from '@/components/NavbarToggleButton'
|
||||
import LanguageSwitch from '@/components/LanguageSwitch.vue'
|
||||
import VueQrcode from 'vue-qrcode'
|
||||
|
||||
export default {
|
||||
name: 'sidebar',
|
||||
components: {
|
||||
NavbarToggleButton,
|
||||
LanguageSwitch,
|
||||
VueQrcode,
|
||||
},
|
||||
props: {
|
||||
|
||||
13
frontend/src/graphql/mutations.js
Normal file
13
frontend/src/graphql/mutations.js
Normal file
@ -0,0 +1,13 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const subscribeNewsletter = gql`
|
||||
mutation($email: String!, $language: String!) {
|
||||
subscribeNewsletter(email: $email, language: $language)
|
||||
}
|
||||
`
|
||||
|
||||
export const unsubscribeNewsletter = gql`
|
||||
mutation($email: String!, $language: String!) {
|
||||
unsubscribeNewsletter(email: $email, language: $language)
|
||||
}
|
||||
`
|
||||
@ -41,7 +41,13 @@
|
||||
"fromCommunity":"Aus der Gemeinschaft",
|
||||
"toCommunity":"An die Gemeinschaft",
|
||||
"noDecay": "Keine Vergänglichkeit"
|
||||
},
|
||||
},
|
||||
"setting": {
|
||||
"newsletter": "Newsletter",
|
||||
"changeNewsletter": "Newsletter Status ändern",
|
||||
"newsletterTrue": "Du bist im Newslettersystem eingetraten.",
|
||||
"newsletterFalse": "Du bist aus Newslettersystem ausgetragen."
|
||||
},
|
||||
"form": {
|
||||
"cancel": "Abbrechen",
|
||||
"reset": "Zurücksetzen",
|
||||
|
||||
@ -42,6 +42,12 @@
|
||||
"toCommunity":"To the community",
|
||||
"noDecay": "No Decay"
|
||||
},
|
||||
"setting": {
|
||||
"newsletter": "Newsletter",
|
||||
"changeNewsletter": "Newsletter status change",
|
||||
"newsletterTrue": "You are subscribed to newsletter system.",
|
||||
"newsletterFalse": "You are unsubscribed from newsletter system."
|
||||
},
|
||||
"form": {
|
||||
"cancel":"Cancel",
|
||||
"reset": "Reset",
|
||||
|
||||
@ -26,6 +26,9 @@ export const mutations = {
|
||||
token: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
newsletterState: (state, newsletterState) => {
|
||||
state.newsletterState = newsletterState
|
||||
},
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
@ -36,6 +39,7 @@ export const actions = {
|
||||
commit('firstName', data.firstName)
|
||||
commit('lastName', data.lastName)
|
||||
commit('description', data.description)
|
||||
commit('newsletterState', data.klickTipp.newsletterState)
|
||||
},
|
||||
logout: ({ commit, state }) => {
|
||||
commit('token', null)
|
||||
@ -44,6 +48,7 @@ export const actions = {
|
||||
commit('firstName', '')
|
||||
commit('lastName', '')
|
||||
commit('description', '')
|
||||
commit('newsletterState', null)
|
||||
localStorage.clear()
|
||||
},
|
||||
}
|
||||
@ -62,6 +67,7 @@ export const store = new Vuex.Store({
|
||||
username: '',
|
||||
description: '',
|
||||
token: null,
|
||||
newsletterState: null,
|
||||
},
|
||||
getters: {},
|
||||
// Syncronous mutation of the state
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
import { mutations, actions } from './store'
|
||||
|
||||
const { language, email, token, username, firstName, lastName, description } = mutations
|
||||
const {
|
||||
language,
|
||||
email,
|
||||
token,
|
||||
username,
|
||||
firstName,
|
||||
lastName,
|
||||
description,
|
||||
newsletterState,
|
||||
} = mutations
|
||||
const { login, logout } = actions
|
||||
|
||||
describe('Vuex store', () => {
|
||||
@ -60,6 +69,14 @@ describe('Vuex store', () => {
|
||||
expect(state.description).toEqual('Nickelbrille')
|
||||
})
|
||||
})
|
||||
|
||||
describe('newsletterState', () => {
|
||||
it('sets the state of newsletterState', () => {
|
||||
const state = { newsletterState: null }
|
||||
newsletterState(state, true)
|
||||
expect(state.newsletterState).toEqual(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('actions', () => {
|
||||
@ -73,11 +90,14 @@ describe('Vuex store', () => {
|
||||
firstName: 'Peter',
|
||||
lastName: 'Lustig',
|
||||
description: 'Nickelbrille',
|
||||
klickTipp: {
|
||||
newsletterState: true,
|
||||
},
|
||||
}
|
||||
|
||||
it('calls seven commits', () => {
|
||||
login({ commit, state }, commitedData)
|
||||
expect(commit).toHaveBeenCalledTimes(6)
|
||||
expect(commit).toHaveBeenCalledTimes(7)
|
||||
})
|
||||
|
||||
it('commits email', () => {
|
||||
@ -109,6 +129,11 @@ describe('Vuex store', () => {
|
||||
login({ commit, state }, commitedData)
|
||||
expect(commit).toHaveBeenNthCalledWith(6, 'description', 'Nickelbrille')
|
||||
})
|
||||
|
||||
it('commits newsletterState', () => {
|
||||
login({ commit, state }, commitedData)
|
||||
expect(commit).toHaveBeenNthCalledWith(7, 'newsletterState', true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('logout', () => {
|
||||
@ -117,7 +142,7 @@ describe('Vuex store', () => {
|
||||
|
||||
it('calls six commits', () => {
|
||||
logout({ commit, state })
|
||||
expect(commit).toHaveBeenCalledTimes(6)
|
||||
expect(commit).toHaveBeenCalledTimes(7)
|
||||
})
|
||||
|
||||
it('commits token', () => {
|
||||
@ -150,6 +175,11 @@ describe('Vuex store', () => {
|
||||
expect(commit).toHaveBeenNthCalledWith(6, 'description', '')
|
||||
})
|
||||
|
||||
it('commits newsletterState', () => {
|
||||
logout({ commit, state })
|
||||
expect(commit).toHaveBeenNthCalledWith(7, 'newsletterState', null)
|
||||
})
|
||||
|
||||
// how to get this working?
|
||||
it.skip('calls localStorage.clear()', () => {
|
||||
const clearStorageMock = jest.fn()
|
||||
|
||||
@ -117,10 +117,6 @@ describe('DashboardLayoutGdd', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('has a locale switch', () => {
|
||||
expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has a logout button', () => {
|
||||
expect(wrapper.findAll('ul').at(3).text()).toBe('logout')
|
||||
})
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
<template>
|
||||
<b-card class="bg-transparent">
|
||||
<div class="w-100 text-center">
|
||||
<vue-qrcode :value="$store.state.email" type="image/png"></vue-qrcode>
|
||||
<vue-qrcode
|
||||
v-if="$store.state.email"
|
||||
:value="$store.state.email"
|
||||
type="image/png"
|
||||
></vue-qrcode>
|
||||
</div>
|
||||
|
||||
<div class="card-profile-stats d-flex justify-content-center mt-md-5">
|
||||
|
||||
@ -12,38 +12,42 @@
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
<b-container>
|
||||
<div>
|
||||
<b-form @keyup.prevent="loadSubmitButton">
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-12 col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.firstname') }}</small>
|
||||
<b-col class="col-12">
|
||||
<small>
|
||||
<b>{{ $t('form.firstname') }}</b>
|
||||
</small>
|
||||
</b-col>
|
||||
<b-col v-if="showUserData" class="h2 col-sm-10 col-md-9">
|
||||
<b-col v-if="showUserData" class="col-12">
|
||||
{{ form.firstName }}
|
||||
</b-col>
|
||||
<b-col v-else class="col-md-9 col-sm-10">
|
||||
<b-col v-else class="col-12">
|
||||
<b-input type="text" v-model="form.firstName"></b-input>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-12 col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.lastname') }}</small>
|
||||
<b-col class="col-12">
|
||||
<small>
|
||||
<b>{{ $t('form.lastname') }}</b>
|
||||
</small>
|
||||
</b-col>
|
||||
<b-col v-if="showUserData" class="h2 col-sm-10 col-md-9">
|
||||
<b-col v-if="showUserData" class="col-12">
|
||||
{{ form.lastName }}
|
||||
</b-col>
|
||||
<b-col v-else class="col-md-9 col-sm-10">
|
||||
<b-col v-else class="col-12">
|
||||
<b-input type="text" v-model="form.lastName"></b-input>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="mb-3" v-show="false">
|
||||
<b-col class="col-12 col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<b-col class="col-12">
|
||||
<small>{{ $t('form.description') }}</small>
|
||||
</b-col>
|
||||
<b-col v-if="showUserData" class="col-sm-10 col-md-9">
|
||||
<b-col v-if="showUserData" class="col-12">
|
||||
{{ form.description }}
|
||||
</b-col>
|
||||
<b-col v-else class="col-sm-10 col-md-9">
|
||||
<b-col v-else class="col-12">
|
||||
<b-textarea rows="3" max-rows="6" v-model="form.description"></b-textarea>
|
||||
</b-col>
|
||||
</b-row>
|
||||
@ -64,7 +68,7 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-form>
|
||||
</b-container>
|
||||
</div>
|
||||
</b-card>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@ -18,10 +18,12 @@
|
||||
|
||||
<div v-if="showLanguage">
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('language') }}</small>
|
||||
<b-col class="col-12">
|
||||
<small>
|
||||
<b>{{ $t('language') }}</b>
|
||||
</small>
|
||||
</b-col>
|
||||
<b-col class="h2 col-md-9 col-sm-10">{{ $store.state.language }}</b-col>
|
||||
<b-col class="col-12">{{ $store.state.language }}</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
@ -29,18 +31,26 @@
|
||||
<div>
|
||||
<b-form @submit.stop.prevent="handleSubmit(onSubmit)">
|
||||
<b-row class="mb-2">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('language') }}</small>
|
||||
<b-col class="col-12">
|
||||
<small>
|
||||
<b>{{ $t('language') }}</b>
|
||||
</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">
|
||||
<b-col class="col-12">
|
||||
<language-switch-select @update-language="updateLanguage" :language="language" />
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row class="text-right">
|
||||
<b-col>
|
||||
<div class="text-right">
|
||||
<b-button type="submit" variant="primary" class="mt-4">
|
||||
<div class="text-right" ref="submitButton">
|
||||
<b-button
|
||||
:variant="loading ? 'default' : 'success'"
|
||||
@click="onSubmit"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
:disabled="loading"
|
||||
>
|
||||
{{ $t('form.save') }}
|
||||
</b-button>
|
||||
</div>
|
||||
@ -62,15 +72,22 @@ export default {
|
||||
return {
|
||||
showLanguage: true,
|
||||
language: '',
|
||||
loading: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateLanguage(e) {
|
||||
this.language = e
|
||||
if (this.language !== this.$store.state.language) {
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = true
|
||||
}
|
||||
},
|
||||
cancelEdit() {
|
||||
this.showLanguage = true
|
||||
},
|
||||
|
||||
async onSubmit() {
|
||||
this.$apollo
|
||||
.query({
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import UserCardNewsletter from './UserCard_Newsletter'
|
||||
import { unsubscribeNewsletter } from '../../../graphql/mutations'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const mockAPIcall = jest.fn()
|
||||
|
||||
const toastErrorMock = jest.fn()
|
||||
const toastSuccessMock = jest.fn()
|
||||
const storeCommitMock = jest.fn()
|
||||
const newsletterStateMock = jest.fn().mockReturnValue(true)
|
||||
|
||||
describe('UserCard_Newsletter', () => {
|
||||
let wrapper
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$store: {
|
||||
state: {
|
||||
language: 'de',
|
||||
email: 'peter@lustig.de',
|
||||
newsletterState: newsletterStateMock,
|
||||
},
|
||||
commit: storeCommitMock,
|
||||
},
|
||||
$toasted: {
|
||||
success: toastSuccessMock,
|
||||
error: toastErrorMock,
|
||||
},
|
||||
$apollo: {
|
||||
mutate: mockAPIcall,
|
||||
},
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(UserCardNewsletter, { localVue, mocks })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div#formusernewsletter').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has an edit BFormCheckbox switch', () => {
|
||||
expect(wrapper.find('.Test-BFormCheckbox').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('unsubscribe with sucess', () => {
|
||||
beforeEach(() => {
|
||||
mockAPIcall.mockResolvedValue({
|
||||
data: {
|
||||
unsubscribeNewsletter: true,
|
||||
},
|
||||
})
|
||||
wrapper.find('input').trigger('change')
|
||||
})
|
||||
|
||||
it('calls the unsubscribe mutation', () => {
|
||||
expect(mockAPIcall).toBeCalledWith({
|
||||
mutation: unsubscribeNewsletter,
|
||||
variables: {
|
||||
email: 'peter@lustig.de',
|
||||
language: 'de',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('updates the store', () => {
|
||||
expect(storeCommitMock).toBeCalledWith('newsletterState', false)
|
||||
})
|
||||
|
||||
it('toasts a success message', () => {
|
||||
expect(toastSuccessMock).toBeCalledWith('setting.newsletterFalse')
|
||||
})
|
||||
})
|
||||
|
||||
describe('unsubscribe with server error', () => {
|
||||
beforeEach(() => {
|
||||
mockAPIcall.mockRejectedValue({
|
||||
message: 'Ouch',
|
||||
})
|
||||
wrapper.find('input').trigger('change')
|
||||
})
|
||||
|
||||
it('resets the newsletterState', () => {
|
||||
expect(wrapper.vm.newsletterState).toBeTruthy()
|
||||
})
|
||||
|
||||
it('toasts an error message', () => {
|
||||
expect(toastErrorMock).toBeCalledWith('Ouch')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
64
frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue
Normal file
64
frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<b-card
|
||||
id="formusernewsletter"
|
||||
class="bg-transparent"
|
||||
style="background-color: #ebebeba3 !important"
|
||||
>
|
||||
<div>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="mb-2 col-12">
|
||||
<small>
|
||||
<b>{{ $t('setting.newsletter') }}</b>
|
||||
</small>
|
||||
</b-col>
|
||||
<b-col class="col-12">
|
||||
<b-form-checkbox
|
||||
class="Test-BFormCheckbox"
|
||||
v-model="newsletterState"
|
||||
name="check-button"
|
||||
switch
|
||||
@change="onSubmit"
|
||||
>
|
||||
{{ newsletterState ? $t('setting.newsletterTrue') : $t('setting.newsletterFalse') }}
|
||||
</b-form-checkbox>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</b-card>
|
||||
</template>
|
||||
<script>
|
||||
import { subscribeNewsletter, unsubscribeNewsletter } from '../../../graphql/mutations'
|
||||
|
||||
export default {
|
||||
name: 'FormUserNewsletter',
|
||||
data() {
|
||||
return {
|
||||
newsletterState: this.$store.state.newsletterState,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async onSubmit() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: this.newsletterState ? subscribeNewsletter : unsubscribeNewsletter,
|
||||
variables: {
|
||||
email: this.$store.state.email,
|
||||
language: this.$store.state.language,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.$store.commit('newsletterState', this.newsletterState)
|
||||
this.$toasted.success(
|
||||
this.newsletterState
|
||||
? this.$t('setting.newsletterTrue')
|
||||
: this.$t('setting.newsletterFalse'),
|
||||
)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.newsletterState = this.$store.state.newsletterState
|
||||
this.$toasted.error(error.message)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -6,6 +6,8 @@
|
||||
<form-user-passwort />
|
||||
<hr />
|
||||
<form-user-language />
|
||||
<hr />
|
||||
<form-user-newsletter />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -13,6 +15,7 @@ import UserCard from './UserProfile/UserCard.vue'
|
||||
import FormUserData from './UserProfile/UserCard_FormUserData.vue'
|
||||
import FormUserPasswort from './UserProfile/UserCard_FormUserPasswort.vue'
|
||||
import FormUserLanguage from './UserProfile/UserCard_Language.vue'
|
||||
import FormUserNewsletter from './UserProfile/UserCard_Newsletter.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -20,6 +23,7 @@ export default {
|
||||
FormUserData,
|
||||
FormUserPasswort,
|
||||
FormUserLanguage,
|
||||
FormUserNewsletter,
|
||||
},
|
||||
props: {
|
||||
balance: { type: Number, default: 0 },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user