diff --git a/backend/package.json b/backend/package.json index f91cbeaee..e79d4d72b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -18,6 +18,7 @@ "apollo-server-express": "^2.25.2", "axios": "^0.21.1", "class-validator": "^0.13.1", + "cors": "^2.8.5", "dotenv": "^10.0.0", "express": "^4.17.1", "graphql": "^15.5.1", diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index 09eee3fb7..827144c13 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -8,8 +8,8 @@ const klicktippConnector = new KlicktippConnector() export const signin = async ( email: string, language: string, - firstName: string, - lastName: string, + firstName?: string, + lastName?: string, ): Promise => { const fields = { fieldFirstName: firstName, @@ -27,7 +27,11 @@ export const signout = async (email: string, language: string): Promise } export const unsubscribe = async (email: string): Promise => { - return await klicktippConnector.unsubscribe(email) + const isLogin = await loginKlicktippUser() + if (isLogin) { + return await klicktippConnector.unsubscribe(email) + } + throw new Error(`Could not unsubscribe ${email}`) } export const getKlickTippUser = async (email: string): Promise => { diff --git a/backend/src/auth/auth.ts b/backend/src/auth/auth.ts index baa94b1ac..a287bfd8f 100644 --- a/backend/src/auth/auth.ts +++ b/backend/src/auth/auth.ts @@ -4,6 +4,7 @@ import { AuthChecker } from 'type-graphql' import decode from '../jwt/decode' import { apiGet } from '../apis/HttpRequest' import CONFIG from '../config' +import encode from '../jwt/encode' /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ export const isAuthorized: AuthChecker = async ({ root, args, context, info }, roles) => { @@ -14,6 +15,7 @@ export const isAuthorized: AuthChecker = async ({ root, args, context, info `${CONFIG.LOGIN_API_URL}checkSessionState?session_id=${decoded.sessionId}`, ) context.sessionId = decoded.sessionId + context.setHeaders.push({ key: 'token', value: encode(decoded.sessionId) }) return result.success } } diff --git a/backend/src/graphql/inputs/KlickTippInputs.ts b/backend/src/graphql/inputs/KlickTippInputs.ts new file mode 100644 index 000000000..cd98dd493 --- /dev/null +++ b/backend/src/graphql/inputs/KlickTippInputs.ts @@ -0,0 +1,10 @@ +import { ArgsType, Field } from 'type-graphql' + +@ArgsType() +export class SubscribeNewsletterArguments { + @Field(() => String) + email: string + + @Field(() => String) + language: string +} diff --git a/backend/src/graphql/models/KlickTipp.ts b/backend/src/graphql/models/KlickTipp.ts new file mode 100644 index 000000000..38e439c7e --- /dev/null +++ b/backend/src/graphql/models/KlickTipp.ts @@ -0,0 +1,13 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { ObjectType, Field } from 'type-graphql' + +@ObjectType() +export class KlickTipp { + constructor(json: any) { + this.newsletterState = json.status !== 'unsubscribed' + } + + @Field(() => Boolean) + newsletterState: boolean +} diff --git a/backend/src/graphql/models/User.ts b/backend/src/graphql/models/User.ts index 47037d483..ca7ed9cf2 100644 --- a/backend/src/graphql/models/User.ts +++ b/backend/src/graphql/models/User.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { ObjectType, Field } from 'type-graphql' +import { KlickTipp } from './KlickTipp' @ObjectType() export class User { @@ -64,4 +65,7 @@ export class User { @Field(() => ID) publisherId: number */ + + @Field(() => KlickTipp) + klickTipp: KlickTipp } diff --git a/backend/src/graphql/resolvers/KlicktippResolver.ts b/backend/src/graphql/resolvers/KlicktippResolver.ts index 48ca46782..5f7e718c3 100644 --- a/backend/src/graphql/resolvers/KlicktippResolver.ts +++ b/backend/src/graphql/resolvers/KlicktippResolver.ts @@ -1,10 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { Resolver, Query, Authorized, Arg } from 'type-graphql' -import { getKlickTippUser, getKlicktippTagMap } from '../../apis/KlicktippController' -import CONFIG from '../../config' -import { TransactionList } from '../models/Transaction' +import { Resolver, Query, Authorized, Arg, Mutation, Args } from 'type-graphql' +import { + getKlickTippUser, + getKlicktippTagMap, + unsubscribe, + signin, +} from '../../apis/KlicktippController' +import { SubscribeNewsletterArguments } from '../inputs/KlickTippInputs' @Resolver() export class KlicktippResolver { @@ -17,4 +21,16 @@ export class KlicktippResolver { async getKlicktippTagMap(): Promise { return await getKlicktippTagMap() } + + @Mutation(() => Boolean) + async unsubscribeNewsletter(@Arg('email') email: string): Promise { + return await unsubscribe(email) + } + + @Mutation(() => Boolean) + async subscribeNewsletter( + @Args() { email, language }: SubscribeNewsletterArguments, + ): Promise { + return await signin(email, language) + } } diff --git a/backend/src/graphql/resolvers/UserResolver.ts b/backend/src/graphql/resolvers/UserResolver.ts index 70523be21..ee8b8dc71 100644 --- a/backend/src/graphql/resolvers/UserResolver.ts +++ b/backend/src/graphql/resolvers/UserResolver.ts @@ -4,10 +4,11 @@ import { Resolver, Query, Args, Arg, Authorized, Ctx, UseMiddleware } from 'type-graphql' import CONFIG from '../../config' import { CheckUsernameResponse } from '../models/CheckUsernameResponse' -import { User } from '../models/User' import { LoginViaVerificationCode } from '../models/LoginViaVerificationCode' import { SendPasswordResetEmailResponse } from '../models/SendPasswordResetEmailResponse' import { UpdateUserInfosResponse } from '../models/UpdateUserInfosResponse' +import { User } from '../models/User' +import encode from '../../jwt/encode' import { ChangePasswordArgs, CheckUsernameArgs, @@ -20,14 +21,12 @@ import { klicktippRegistrationMiddleware, klicktippNewsletterStateMiddleware, } from '../../middleware/klicktippMiddleware' -import encode from '../../jwt/encode' import { CheckEmailResponse } from '../models/CheckEmailResponse' - @Resolver() export class UserResolver { - @Query(() => String) + @Query(() => User) @UseMiddleware(klicktippNewsletterStateMiddleware) - async login(@Args() { email, password }: UnsecureLoginArgs): Promise { + async login(@Args() { email, password }: UnsecureLoginArgs, @Ctx() context: any): Promise { email = email.trim().toLowerCase() const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password }) @@ -36,10 +35,9 @@ export class UserResolver { throw new Error(result.data) } - const data = result.data - const sessionId = data.session_id - delete data.session_id - return encode({ sessionId, user: new User(data.user) }) + context.setHeaders.push({ key: 'token', value: encode(result.data.session_id) }) + + return new User(result.data.user) } @Query(() => LoginViaVerificationCode) diff --git a/backend/src/index.ts b/backend/src/index.ts index 057da0e94..7e1d8286b 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -2,6 +2,7 @@ import 'reflect-metadata' import express from 'express' +import cors from 'cors' import { buildSchema } from 'type-graphql' import { ApolloServer } from 'apollo-server-express' import { RowDataPacket } from 'mysql2/promise' @@ -23,14 +24,15 @@ import { isAuthorized } from './auth/auth' const DB_VERSION = '0001-init_db' -const context = (req: any) => { - const authorization = req.req.headers.authorization +const context = (args: any) => { + const authorization = args.req.headers.authorization let token = null if (authorization) { - token = req.req.headers.authorization.replace(/^Bearer /, '') + token = authorization.replace(/^Bearer /, '') } const context = { token, + setHeaders: [], } return context } @@ -62,8 +64,31 @@ async function main() { // Express Server const server = express() + const corsOptions = { + origin: '*', + exposedHeaders: ['token'], + } + + server.use(cors(corsOptions)) + + const plugins = [ + { + requestDidStart() { + return { + willSendResponse(requestContext: any) { + const { setHeaders = [] } = requestContext.context + setHeaders.forEach(({ key, value }: { [key: string]: string }) => { + requestContext.response.http.headers.append(key, value) + }) + return requestContext + }, + } + }, + }, + ] + // Apollo Server - const apollo = new ApolloServer({ schema, playground, context }) + const apollo = new ApolloServer({ schema, playground, context, plugins }) apollo.applyMiddleware({ app: server }) // Start Server diff --git a/backend/src/jwt/decode.ts b/backend/src/jwt/decode.ts index a414e0c41..47cf62154 100644 --- a/backend/src/jwt/decode.ts +++ b/backend/src/jwt/decode.ts @@ -7,15 +7,12 @@ import CONFIG from '../config/' export default (token: string): any => { if (!token) return null let sessionId = null - const email = null try { const decoded = jwt.verify(token, CONFIG.JWT_SECRET) sessionId = decoded.sub - // email = decoded.email return { token, sessionId, - email, } } catch (err) { return null diff --git a/backend/src/jwt/encode.ts b/backend/src/jwt/encode.ts index 477644dc7..9c5145e6d 100644 --- a/backend/src/jwt/encode.ts +++ b/backend/src/jwt/encode.ts @@ -5,13 +5,9 @@ import jwt from 'jsonwebtoken' import CONFIG from '../config/' // Generate an Access Token -export default function encode(data: any): string { - const { user, sessionId } = data - const { email, language, firstName, lastName } = user - const token = jwt.sign({ email, language, firstName, lastName, sessionId }, CONFIG.JWT_SECRET, { +export default function encode(sessionId: string): string { + const token = jwt.sign({ sessionId }, CONFIG.JWT_SECRET, { expiresIn: CONFIG.JWT_EXPIRES_IN, - // issuer: CONFIG.GRAPHQL_URI, - // audience: CONFIG.CLIENT_URI, subject: sessionId.toString(), }) return token diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index 04902fa65..39c40d2e8 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -1,5 +1,6 @@ import { MiddlewareFn } from 'type-graphql' import { signin, getKlickTippUser } from '../apis/KlicktippController' +import { KlickTipp } from '../graphql/models/KlickTipp' import decode from '../jwt/decode' export const klicktippRegistrationMiddleware: MiddlewareFn = async ( @@ -20,9 +21,11 @@ export const klicktippNewsletterStateMiddleware: MiddlewareFn = async ( next, ) => { const result = await next() - const decodedResult = decode(result) - console.log('result', decodedResult) - const klickTippUser = getKlickTippUser(decodedResult.email) + const klickTippUser = await getKlickTippUser(result.email) console.log('klickTippUser', klickTippUser) + const klickTipp = new KlickTipp(klickTippUser) + console.log('klickTipp', klickTipp) + result.klickTipp = klickTipp + console.log('result', result) return result } diff --git a/community_server/src/Template/StateBalances/overview_gdt.ctp b/community_server/src/Template/StateBalances/overview_gdt.ctp index 198256e23..f293b93be 100644 --- a/community_server/src/Template/StateBalances/overview_gdt.ctp +++ b/community_server/src/Template/StateBalances/overview_gdt.ctp @@ -50,8 +50,8 @@ $this->assign('header', $header); element('printGDT', ['number' => $entry['amount']*100.0]); ?> - element('printEuro', ['number' => $entry['amount']]); ?> - element('printEuro', ['number' => $entry['amount2']]) ?> + element('printEuro', ['number' => $entry['amount']*100.0]); ?> + element('printEuro', ['number' => $entry['amount2']*100.0]) ?>
@@ -96,8 +96,8 @@ $this->assign('header', $header); element('printGDT', ['number' => $gdtEntry['amount']*100.0]); ?> - element('printEuro', ['number' => $gdtEntry['amount']]); ?> - element('printEuro', ['number' => $gdtEntry['amount2']]) ?> + element('printEuro', ['number' => $gdtEntry['amount']*100.0]); ?> + element('printEuro', ['number' => $gdtEntry['amount2']*100.0]) ?>
diff --git a/frontend/package.json b/frontend/package.json index 59b34cc9d..4bc621916 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -72,7 +72,6 @@ "vue-good-table": "^2.21.3", "vue-i18n": "^8.22.4", "vue-jest": "^3.0.7", - "vue-jwt-decode": "^0.1.0", "vue-loading-overlay": "^3.4.2", "vue-moment": "^4.1.0", "vue-qrcode": "^0.3.5", diff --git a/frontend/src/components/LanguageSwitchSelect.vue b/frontend/src/components/LanguageSwitchSelect.vue new file mode 100644 index 000000000..518bcf6cf --- /dev/null +++ b/frontend/src/components/LanguageSwitchSelect.vue @@ -0,0 +1,40 @@ + + diff --git a/frontend/src/components/Transaction.spec.js b/frontend/src/components/Transaction.spec.js new file mode 100644 index 000000000..43dc44782 --- /dev/null +++ b/frontend/src/components/Transaction.spec.js @@ -0,0 +1,31 @@ +import { mount } from '@vue/test-utils' +import Transaction from './Transaction' + +const localVue = global.localVue + +describe('Transaction', () => { + let wrapper + + const mocks = { + $i18n: { + locale: 'en', + }, + $t: jest.fn((t) => t), + $n: jest.fn((n) => n), + $d: jest.fn((d) => d), + } + + const Wrapper = () => { + return mount(Transaction, { localVue, mocks }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders the component', () => { + expect(wrapper.find('div.gdt-transaction-list-item').exists()).toBeTruthy() + }) + }) +}) diff --git a/frontend/src/components/Transaction.vue b/frontend/src/components/Transaction.vue new file mode 100644 index 000000000..03b559463 --- /dev/null +++ b/frontend/src/components/Transaction.vue @@ -0,0 +1,124 @@ + + diff --git a/frontend/src/components/TransactionCollapse.spec.js b/frontend/src/components/TransactionCollapse.spec.js new file mode 100644 index 000000000..f27c3ae66 --- /dev/null +++ b/frontend/src/components/TransactionCollapse.spec.js @@ -0,0 +1,152 @@ +import { mount } from '@vue/test-utils' +import TransactionCollapse from './TransactionCollapse' + +const localVue = global.localVue + +describe('TransactionCollapse', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + $n: jest.fn((n) => n), + } + + const Wrapper = (propsData) => { + return mount(TransactionCollapse, { localVue, mocks, propsData }) + } + + describe('mount with gdtEntryType: 1', () => { + beforeEach(() => { + const propsData = { + amount: 100, + gdt: 110, + factor: 22, + gdtEntryType: 1, + } + + wrapper = Wrapper(propsData) + }) + + it('renders the component', () => { + expect(wrapper.find('div.gdt-transaction-collapse').exists()).toBeTruthy() + }) + + it('checks the prop gdtEntryType ', () => { + expect(wrapper.props().gdtEntryType).toBe(1) + }) + + it('renders the component collapse-header', () => { + expect(wrapper.find('.gdt-list-collapse-header-text')).toBeTruthy() + }) + + it('renders the component collapse-headline', () => { + expect(wrapper.find('#collapse-headline').text()).toBe('gdt.calculation') + }) + + it('renders the component collapse-first', () => { + expect(wrapper.find('#collapse-first').text()).toBe('gdt.factor') + }) + + it('renders the component collapse-second', () => { + expect(wrapper.find('#collapse-second').text()).toBe('gdt.formula') + }) + + it('renders the component collapse-firstMath', () => { + expect(wrapper.find('#collapse-firstMath').text()).toBe('22 GDT pro €') + }) + + it('renders the component collapse-secondMath', () => { + expect(wrapper.find('#collapse-secondMath').text()).toBe('100 € * 22 GDT / € = 110 GDT') + }) + }) + + describe('mount with gdtEntryType: 7', () => { + beforeEach(() => { + const propsData = { + amount: 100, + gdt: 2200, + factor: 22, + gdtEntryType: 7, + } + + wrapper = Wrapper(propsData) + }) + + it('renders the component', () => { + expect(wrapper.find('div.gdt-transaction-collapse').exists()).toBeTruthy() + }) + + it('checks the prop gdtEntryType ', () => { + expect(wrapper.props().gdtEntryType).toBe(7) + }) + + it('renders the component collapse-header', () => { + expect(wrapper.find('.gdt-list-collapse-header-text')).toBeTruthy() + }) + + it('renders the component collapse-headline', () => { + expect(wrapper.find('#collapse-headline').text()).toBe('gdt.conversion-gdt-euro') + }) + + it('renders the component collapse-first', () => { + expect(wrapper.find('#collapse-first').text()).toBe('gdt.raise') + }) + + it('renders the component collapse-second', () => { + expect(wrapper.find('#collapse-second').text()).toBe('gdt.conversion') + }) + + it('renders the component collapse-firstMath', () => { + expect(wrapper.find('#collapse-firstMath').text()).toBe('2200 %') + }) + + it('renders the component collapse-secondMath', () => { + expect(wrapper.find('#collapse-secondMath').text()).toBe('100 GDT * 2200 % = 2200 GDT') + }) + }) + + describe('mount with gdtEntryType: 4', () => { + beforeEach(() => { + const propsData = { + amount: 100, + gdt: 2200, + factor: 22, + gdtEntryType: 4, + } + + wrapper = Wrapper(propsData) + }) + + it('renders the component', () => { + expect(wrapper.find('div.gdt-transaction-collapse').exists()).toBeTruthy() + }) + + it('checks the prop gdtEntryType ', () => { + expect(wrapper.props().gdtEntryType).toBe(4) + }) + + it('renders the component collapse-header', () => { + expect(wrapper.find('.gdt-list-collapse-header-text')).toBeTruthy() + }) + + it('renders the component collapse-headline', () => { + expect(wrapper.find('#collapse-headline').text()).toBe('gdt.publisher') + }) + + it('renders the component collapse-first', () => { + expect(wrapper.find('#collapse-first').text()).toBe('') + }) + + it('renders the component collapse-second', () => { + expect(wrapper.find('#collapse-second').text()).toBe('') + }) + + it('renders the component collapse-firstMath', () => { + expect(wrapper.find('#collapse-firstMath').text()).toBe('') + }) + + it('renders the component collapse-secondMath', () => { + expect(wrapper.find('#collapse-secondMath').text()).toBe('') + }) + }) +}) diff --git a/frontend/src/components/TransactionCollapse.vue b/frontend/src/components/TransactionCollapse.vue new file mode 100644 index 000000000..854282a43 --- /dev/null +++ b/frontend/src/components/TransactionCollapse.vue @@ -0,0 +1,76 @@ + + diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 06c0cc6b3..089b24a83 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -2,7 +2,17 @@ import gql from 'graphql-tag' export const login = gql` query ($email: String!, $password: String!) { - login(email: $email, password: $password) + login(email: $email, password: $password) { + email + username + firstName + lastName + language + description + klickTipp { + newsletterState + } + } } ` diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 1720f8d00..71b14cda4 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -64,6 +64,7 @@ "change": "ändern", "change-password": "Passwort ändern", "change-name": "Name ändern", + "changeLanguage": "Sprache ändern", "amount":"Betrag", "memo":"Nachricht", "message":"Nachricht", @@ -142,15 +143,6 @@ "send_gradido":"Gradido versenden", "add_work":"neuer Gemeinschaftsbeitrag" }, - "profil": { - "activity": { - "new":"Neue Gemeinschaftsstunden eintragen", - "list":"Meine Gemeinschaftsstunden Liste" - }, - "user-data": { - "change-success": "Deine Daten wurden gespeichert." - } - }, "navbar" : { "my-profil":"Mein Profil", "settings":"Einstellungen", @@ -188,8 +180,8 @@ "formula":"Berechungsformel", "no-transactions":"Du hast zur Zeit keine Transaktionen", "publisher":"Dein geworbenes Mitglied hat einen Beitrag bezahlt", - "gdt-receive":"Aktion", - "your-share":"Geworbenes Mitglied", + "action":"Aktion", + "recruited-member":"Geworbenes Mitglied", "contribution":"Beitrag" } } diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 005c3b914..c24129616 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -64,6 +64,7 @@ "change": "change", "change-password": "Change password", "change-name": "Change name", + "changeLanguage": "Change language", "amount":"Amount", "memo":"Message", "message":"Message", @@ -142,16 +143,6 @@ "send_gradido":"Send Gradido", "add_work":"New Community Contribution" }, - "profil": { - "transactions":"transactions", - "activity": { - "new":"Register new community hours", - "list":"My Community Hours List" - }, - "user-data": { - "change-success": "Your data has been saved." - } - }, "navbar" : { "my-profil":"My profile", "settings":"Settings", @@ -189,8 +180,8 @@ "formula": "Calculation formula", "no-transactions":"You currently have no transactions", "publisher":"A member you referred has paid a contribution", - "gdt-receive":"GDT receive", - "your-share":"Your share", + "action":"Action", + "recruited-member":"Recruited Member", "contribution":"Contribution" } } diff --git a/frontend/src/main.js b/frontend/src/main.js index 823df516c..0b0e98e2d 100755 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -20,7 +20,11 @@ const authLink = new ApolloLink((operation, forward) => { Authorization: token && token.length > 0 ? `Bearer ${token}` : '', }, }) - return forward(operation) + return forward(operation).map((response) => { + const newToken = operation.getContext().response.headers.get('token') + if (newToken) store.commit('token', newToken) + return response + }) }) const apolloClient = new ApolloClient({ diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js index 77c7096ad..00f8369d2 100644 --- a/frontend/src/store/store.js +++ b/frontend/src/store/store.js @@ -1,7 +1,6 @@ import Vue from 'vue' import Vuex from 'vuex' import createPersistedState from 'vuex-persistedstate' -import VueJwtDecode from 'vue-jwt-decode' Vue.use(Vuex) @@ -30,15 +29,13 @@ export const mutations = { } export const actions = { - login: ({ dispatch, commit }, token) => { - const decoded = VueJwtDecode.decode(token) - commit('token', token) - commit('email', decoded.email) - commit('language', decoded.language) - commit('username', decoded.username) - commit('firstName', decoded.firstName) - commit('lastName', decoded.lastName) - commit('description', decoded.description) + login: ({ dispatch, commit }, data) => { + commit('email', data.email) + commit('language', data.language) + commit('username', data.username) + commit('firstName', data.firstName) + commit('lastName', data.lastName) + commit('description', data.description) }, logout: ({ commit, state }) => { commit('token', null) diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index 99a37451e..c067a6e49 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -1,15 +1,4 @@ import { mutations, actions } from './store' -import VueJwtDecode from 'vue-jwt-decode' - -jest.mock('vue-jwt-decode') -VueJwtDecode.decode.mockReturnValue({ - email: 'user@example.org', - language: 'de', - username: 'peter', - firstName: 'Peter', - lastName: 'Lustig', - description: 'Nickelbrille', -}) const { language, email, token, username, firstName, lastName, description } = mutations const { login, logout } = actions @@ -77,46 +66,48 @@ describe('Vuex store', () => { describe('login', () => { const commit = jest.fn() const state = {} - const commitedData = 'token' + const commitedData = { + email: 'user@example.org', + language: 'de', + username: 'peter', + firstName: 'Peter', + lastName: 'Lustig', + description: 'Nickelbrille', + } it('calls seven commits', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenCalledTimes(7) - }) - - it('commits token', () => { - login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(1, 'token', 'token') + expect(commit).toHaveBeenCalledTimes(6) }) it('commits email', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(2, 'email', 'user@example.org') + expect(commit).toHaveBeenNthCalledWith(1, 'email', 'user@example.org') }) it('commits language', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(3, 'language', 'de') + expect(commit).toHaveBeenNthCalledWith(2, 'language', 'de') }) it('commits username', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(4, 'username', 'peter') + expect(commit).toHaveBeenNthCalledWith(3, 'username', 'peter') }) it('commits firstName', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(5, 'firstName', 'Peter') + expect(commit).toHaveBeenNthCalledWith(4, 'firstName', 'Peter') }) it('commits lastName', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(6, 'lastName', 'Lustig') + expect(commit).toHaveBeenNthCalledWith(5, 'lastName', 'Lustig') }) it('commits description', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenNthCalledWith(7, 'description', 'Nickelbrille') + expect(commit).toHaveBeenNthCalledWith(6, 'description', 'Nickelbrille') }) }) diff --git a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue index 3bdc9f42c..1ad4ba13e 100644 --- a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue @@ -17,134 +17,14 @@ } in transactionsGdt" :key="transactionId" > -
- -
- -
- - -
- - i - -
- - - - - -
-
{{ $t('gdt.gdt-receive') }}
-
{{ $t('gdt.credit') }}
-
-
-
{{ comment }}
-
{{ $n(gdt, 'decimal') }} GDT
-
-
- - -
-
{{ $t('gdt.your-share') }}
-
{{ $t('gdt.credit') }}
-
-
-
5%
-
{{ $n(amount, 'decimal') }} GDT
-
-
- - -
-
{{ $t('gdt.contribution') }}
-
{{ $t('gdt.credit') }}
-
-
-
{{ $n(amount, 'decimal') }} €
-
{{ $n(gdt, 'decimal') }} GDT
-
-
- - - - - -
- {{ $t('form.memo') }} -
-
- {{ comment }} -
-
- - - -
- {{ $t('form.date') }} -
-
- {{ $d($moment(date), 'long') }} {{ $i18n.locale === 'de' ? 'Uhr' : '' }} -
-
-
- - - - -
- - -
- {{ $t('gdt.conversion-gdt-euro') }} -
-
- {{ $t('gdt.publisher') }} -
-
{{ $t('gdt.calculation') }}
-
- - - -
-
{{ $t('gdt.raise') }}
-
{{ $t('gdt.conversion') }}
-
-
-
{{ factor * 100 }} %
-
- {{ $n(amount, 'decimal') }} GDT * {{ factor * 100 }} % = - {{ $n(gdt, 'decimal') }} GDT -
-
-
- - -
-
-
- - - -
-
{{ $t('gdt.factor') }}
-
{{ $t('gdt.formula') }}
-
-
-
{{ factor }} GDT pro €
-
- {{ $n(amount, 'decimal') }} € * {{ factor }} GDT / € = - {{ $n(gdt, 'decimal') }} GDT -
-
-
-
-
- +
import { listGDTEntriesQuery } from '../../../graphql/queries' import PaginationButtons from '../../../components/PaginationButtons' - -function iconByType(typeId) { - switch (typeId) { - case 1: - case 2: - case 3: - case 5: - case 6: - return { icon: 'heart', classes: 'gradido-global-color-accent' } - case 4: - return { icon: 'person-check', classes: 'gradido-global-color-accent' } - case 7: - return { icon: 'gift', classes: 'gradido-global-color-accent' } - } -} +import Transaction from '../../../components/Transaction.vue' export default { name: 'gdt-transaction-list', components: { PaginationButtons, + Transaction, }, data() { return { @@ -223,18 +90,6 @@ export default { this.$toasted.error(error.message) }) }, - getIcon(givenType) { - const type = iconByType(givenType) - if (type) - return { - icon: type.icon, - class: type.classes + ' m-mb-1 font2em', - } - this.throwError('no icon to given type: ' + givenType) - }, - throwError(msg) { - throw new Error(msg) - }, showNext() { this.currentPage++ this.updateGdt() diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index 1a9549d41..6bc889be3 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -27,6 +27,11 @@ describe('Register', () => { $apollo: { query: resgisterUserQueryMock, }, + $store: { + state: { + language: null, + }, + }, } const stubs = { @@ -43,7 +48,7 @@ describe('Register', () => { }) it('renders the Register form', () => { - expect(wrapper.find('div.register-form').exists()).toBeTruthy() + expect(wrapper.find('div#registerform').exists()).toBeTruthy() }) describe('Register header', () => { @@ -86,11 +91,11 @@ describe('Register', () => { expect(wrapper.find('input[name="form.passwordRepeat"]').exists()).toBeTruthy() }) it('has Language selected field', () => { - expect(wrapper.find('#selectedLanguage').exists()).toBeTruthy() + expect(wrapper.find('.selectedLanguage').exists()).toBeTruthy() }) it('selected Language value de', async () => { - wrapper.find('#selectedLanguage').findAll('option').at(1).setSelected() - expect(wrapper.find('#selectedLanguage').element.value).toBe('de') + wrapper.find('.selectedLanguage').findAll('option').at(1).setSelected() + expect(wrapper.find('.selectedLanguage').element.value).toBe('de') }) it('has 1 checkbox input fields', () => { @@ -133,14 +138,14 @@ describe('Register', () => { wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net') wrapper.find('input[name="form.password"]').setValue('Aa123456') wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456') - wrapper.find('#selectedLanguage').findAll('option').at(1).setSelected() + wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() wrapper.find('input[name="site.signup.agree"]').setChecked(true) }) it('reset selected value language', async () => { await wrapper.find('button.ml-2').trigger('click') await flushPromises() - expect(wrapper.find('#selectedLanguage').element.value).toBe('') + expect(wrapper.find('.language-switch-select').element.value).toBe(undefined) }) it('resets the firstName field after clicking the reset button', async () => { @@ -187,7 +192,7 @@ describe('Register', () => { wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net') wrapper.find('input[name="form.password"]').setValue('Aa123456') wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456') - wrapper.find('#selectedLanguage').findAll('option').at(1).setSelected() + wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() }) describe('server sends back error', () => { diff --git a/frontend/src/views/Pages/Register.vue b/frontend/src/views/Pages/Register.vue index f8e7eefd0..8c70f94e6 100755 --- a/frontend/src/views/Pages/Register.vue +++ b/frontend/src/views/Pages/Register.vue @@ -1,5 +1,5 @@