Merge pull request #3297 from gradido/update_user_settings_gms

feat(frontend): update gms user settings
This commit is contained in:
einhornimmond 2024-03-07 10:01:02 +01:00 committed by GitHub
commit 0f7921bf5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 743 additions and 152 deletions

View File

@ -1,6 +1,8 @@
import { IsBoolean, IsInt, IsString } from 'class-validator'
import { IsBoolean, IsEnum, IsInt, IsString } from 'class-validator'
import { ArgsType, Field, InputType, Int } from 'type-graphql'
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
import { Location } from '@model/Location'
import { isValidLocation } from '@/graphql/validator/Location'
@ -44,19 +46,19 @@ export class UpdateUserInfosArgs {
@IsBoolean()
hideAmountGDT?: boolean
@Field({ nullable: true, defaultValue: true })
@Field({ nullable: true })
@IsBoolean()
gmsAllowed?: boolean
@Field(() => Int, { nullable: true, defaultValue: 0 })
@IsInt()
gmsPublishName?: number | null
@Field(() => GmsPublishNameType, { nullable: true })
@IsEnum(GmsPublishNameType)
gmsPublishName?: GmsPublishNameType | null
@Field(() => Location, { nullable: true })
@isValidLocation()
gmsLocation?: Location | null
@Field(() => Int, { nullable: true, defaultValue: 2 })
@IsInt()
gmsPublishLocation?: number | null
@Field(() => GmsPublishLocationType, { nullable: true })
@IsEnum(GmsPublishLocationType)
gmsPublishLocation?: GmsPublishLocationType | null
}

View File

@ -1,6 +1,9 @@
import { User as dbUser } from '@entity/User'
import { ObjectType, Field, Int } from 'type-graphql'
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
import { KlickTipp } from './KlickTipp'
@ObjectType()
@ -29,6 +32,9 @@ export class User {
this.hasElopage = null
this.hideAmountGDD = user.hideAmountGDD
this.hideAmountGDT = user.hideAmountGDT
this.gmsAllowed = user.gmsAllowed
this.gmsPublishName = user.gmsPublishName
this.gmsPublishLocation = user.gmsPublishLocation
}
}
@ -74,6 +80,15 @@ export class User {
@Field(() => Boolean)
hideAmountGDT: boolean
@Field(() => Boolean)
gmsAllowed: boolean
@Field(() => GmsPublishNameType, { nullable: true })
gmsPublishName: GmsPublishNameType | null
@Field(() => GmsPublishLocationType, { nullable: true })
gmsPublishLocation: GmsPublishLocationType | null
// This is not the users publisherId, but the one of the users who recommend him
@Field(() => Int, { nullable: true })
publisherId: number | null

View File

@ -15,8 +15,6 @@ import { ApolloServerTestClient } from 'apollo-server-testing'
import { GraphQLError } from 'graphql'
import { v4 as uuidv4 } from 'uuid'
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
import { cleanDB, testEnvironment } from '@test/helpers'
import { logger } from '@test/testSetup'
@ -534,9 +532,6 @@ describe('send coins', () => {
mutation: updateUserInfos,
variables: {
alias: 'bob',
gmsAllowed: true,
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
},
})
await mutate({

View File

@ -1303,8 +1303,10 @@ describe('UserResolver', () => {
mutation: updateUserInfos,
variables: {
gmsAllowed: false,
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL,
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE,
gmsPublishName:
GmsPublishNameType[GmsPublishNameType.GMS_PUBLISH_NAME_FIRST_INITIAL],
gmsPublishLocation:
GmsPublishLocationType[GmsPublishLocationType.GMS_LOCATION_TYPE_APPROXIMATE],
},
})
await expect(User.find()).resolves.toEqual([
@ -1326,9 +1328,11 @@ describe('UserResolver', () => {
mutation: updateUserInfos,
variables: {
gmsAllowed: true,
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
gmsPublishName:
GmsPublishNameType[GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS],
gmsLocation: loc,
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
gmsPublishLocation:
GmsPublishLocationType[GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM],
},
})
await expect(User.find()).resolves.toEqual([
@ -2674,9 +2678,6 @@ describe('UserResolver', () => {
mutation: updateUserInfos,
variables: {
alias: 'bibi',
gmsAllowed: true,
gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS,
gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM,
},
})
})

View File

@ -19,8 +19,6 @@ import { SearchUsersFilters } from '@arg/SearchUsersFilters'
import { SetUserRoleArgs } from '@arg/SetUserRoleArgs'
import { UnsecureLoginArgs } from '@arg/UnsecureLoginArgs'
import { UpdateUserInfosArgs } from '@arg/UpdateUserInfosArgs'
import { GmsPublishLocationType } from '@enum/GmsPublishLocationType'
import { GmsPublishNameType } from '@enum/GmsPublishNameType'
import { OptInType } from '@enum/OptInType'
import { Order } from '@enum/Order'
import { PasswordEncryptionType } from '@enum/PasswordEncryptionType'
@ -561,17 +559,6 @@ export class UserResolver {
logger.info(
`updateUserInfos(${firstName}, ${lastName}, ${alias}, ${language}, ***, ***, ${hideAmountGDD}, ${hideAmountGDT}, ${gmsAllowed}, ${gmsPublishName}, ${gmsLocation}, ${gmsPublishLocation})...`,
)
// check default arg settings
if (gmsAllowed === null || gmsAllowed === undefined) {
gmsAllowed = true
}
if (!gmsPublishName) {
gmsPublishName = GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS
}
if (!gmsPublishLocation) {
gmsPublishLocation = GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM
}
const user = getUser(context)
// try {
if (firstName) {
@ -619,13 +606,18 @@ export class UserResolver {
if (hideAmountGDT !== undefined) {
user.hideAmountGDT = hideAmountGDT
}
user.gmsAllowed = gmsAllowed
user.gmsPublishName = gmsPublishName
if (gmsAllowed !== undefined) {
user.gmsAllowed = gmsAllowed
}
if (gmsPublishName !== null && gmsPublishName !== undefined) {
user.gmsPublishName = gmsPublishName
}
if (gmsLocation) {
user.location = Location2Point(gmsLocation)
}
user.gmsPublishLocation = gmsPublishLocation
if (gmsPublishLocation !== null && gmsPublishLocation !== undefined) {
user.gmsPublishLocation = gmsPublishLocation
}
// } catch (err) {
// console.log('error:', err)
// }

View File

@ -35,9 +35,9 @@ export const updateUserInfos = gql`
$hideAmountGDD: Boolean
$hideAmountGDT: Boolean
$gmsAllowed: Boolean
$gmsPublishName: Int
$gmsPublishName: GmsPublishNameType
$gmsLocation: Location
$gmsPublishLocation: Int
$gmsPublishLocation: GmsPublishLocationType
) {
updateUserInfos(
firstName: $firstName

View File

@ -26,7 +26,7 @@ EMAIL_CODE_REQUEST_TIME=10
# config versions
DATABASE_CONFIG_VERSION=v1.2022-03-18
BACKEND_CONFIG_VERSION=v21.2024-01-06
FRONTEND_CONFIG_VERSION=v5.2024-01-08
FRONTEND_CONFIG_VERSION=v6.2024-02-27
ADMIN_CONFIG_VERSION=v2.2024-01-04
FEDERATION_CONFIG_VERSION=v2.2023-08-24
FEDERATION_DHT_CONFIG_VERSION=v4.2024-01-17

View File

@ -21,3 +21,5 @@ META_DESCRIPTION_EN="Gratitude is the currency of the new age. More and more peo
META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem"
META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System"
META_AUTHOR="Bernd Hückstädt - Gradido-Akademie"
GMS_ACTIVE=false

View File

@ -24,3 +24,5 @@ META_DESCRIPTION_EN=$META_DESCRIPTION_EN
META_KEYWORDS_DE=$META_KEYWORDS_DE
META_KEYWORDS_EN=$META_KEYWORDS_EN
META_AUTHOR=$META_AUTHOR
GMS_ACTIVE=$GMS_ACTIVE

View File

@ -71,4 +71,16 @@ export default {
.text-color-gdd-yellow {
color: rgb(197 141 56);
}
.dropdown > .dropdown-toggle {
border-radius: 17px;
height: 50px;
text-align: left;
}
.dropdown-toggle::after {
float: right;
top: 50%;
transform: translateY(-50%);
position: relative;
}
</style>

View File

@ -90,20 +90,3 @@ export default {
},
}
</script>
<style>
.community-switch > div,
.community-switch ul.dropdown-menu {
width: 100%;
}
.community-switch > div > button {
border-radius: 17px;
height: 50px;
text-align: left;
}
.community-switch .dropdown-toggle::after {
float: right;
top: 50%;
transform: translateY(-50%);
position: relative;
}
</style>

View File

@ -0,0 +1,8 @@
<template>
<b-button>{{ $t('settings.GMS.location.button') }}</b-button>
</template>
<script>
export default {
name: 'UserGMSLocation',
}
</script>

View File

@ -0,0 +1,79 @@
import { mount } from '@vue/test-utils'
import UserGMSLocationFormat from './UserGMSLocationFormat.vue'
import { toastErrorSpy } from '@test/testSetup'
const mockAPIcall = jest.fn()
const storeCommitMock = jest.fn()
const localVue = global.localVue
describe('UserGMSLocationFormat', () => {
let wrapper
beforeEach(() => {
wrapper = mount(UserGMSLocationFormat, {
mocks: {
$t: (key) => key, // Mocking the translation function
$store: {
state: {
gmsPublishLocation: null,
},
commit: storeCommitMock,
},
$apollo: {
mutate: mockAPIcall,
},
},
localVue,
propsData: {
selectedOption: 'GMS_LOCATION_TYPE_RANDOM',
},
})
})
afterEach(() => {
wrapper.destroy()
})
it('renders the correct dropdown options', () => {
const dropdownItems = wrapper.findAll('.dropdown-item')
expect(dropdownItems.length).toBe(3)
const labels = dropdownItems.wrappers.map((item) => item.text())
expect(labels).toEqual([
'settings.GMS.publish-location.exact',
'settings.GMS.publish-location.approximate',
'settings.GMS.publish-location.random',
])
})
it('updates selected option on click', async () => {
const dropdownItem = wrapper.findAll('.dropdown-item').at(1) // Click the second item
await dropdownItem.trigger('click')
expect(wrapper.emitted().gmsPublishLocation).toBeTruthy()
expect(wrapper.emitted().gmsPublishLocation.length).toBe(1)
expect(wrapper.emitted().gmsPublishLocation[0]).toEqual(['GMS_LOCATION_TYPE_APPROXIMATE'])
})
it('does not update when clicking on already selected option', async () => {
const dropdownItem = wrapper.findAll('.dropdown-item').at(2) // Click the third item (which is already selected)
await dropdownItem.trigger('click')
expect(wrapper.emitted().gmsPublishLocation).toBeFalsy()
})
describe('update with error', () => {
beforeEach(async () => {
mockAPIcall.mockRejectedValue({
message: 'Ouch',
})
const dropdownItem = wrapper.findAll('.dropdown-item').at(1) // Click the second item
await dropdownItem.trigger('click')
})
it('toasts an error message', () => {
expect(toastErrorSpy).toBeCalledWith('Ouch')
})
})
})

View File

@ -0,0 +1,73 @@
<template>
<div class="user-gms-location-format">
<b-dropdown v-model="selectedOption">
<template slot="button-content">{{ selectedOptionLabel }}</template>
<b-dropdown-item
v-for="option in dropdownOptions"
@click.prevent="update(option)"
:key="option.value"
:value="option.value"
>
{{ option.label }}
</b-dropdown-item>
</b-dropdown>
</div>
</template>
<script>
import { updateUserInfos } from '@/graphql/mutations'
export default {
name: 'UserGMSLocationFormat',
data() {
return {
selectedOption: this.$store.state.gmsPublishLocation ?? 'GMS_LOCATION_TYPE_RANDOM',
dropdownOptions: [
{
label: this.$t('settings.GMS.publish-location.exact'),
value: 'GMS_LOCATION_TYPE_EXACT',
},
{
label: this.$t('settings.GMS.publish-location.approximate'),
value: 'GMS_LOCATION_TYPE_APPROXIMATE',
},
{
label: this.$t('settings.GMS.publish-location.random'),
value: 'GMS_LOCATION_TYPE_RANDOM',
},
],
}
},
computed: {
selectedOptionLabel() {
return this.dropdownOptions.find((option) => option.value === this.selectedOption).label
},
},
methods: {
async update(option) {
if (option.value === this.selectedOption) {
return
}
try {
await this.$apollo.mutate({
mutation: updateUserInfos,
variables: {
gmsPublishLocation: option.value,
},
})
this.toastSuccess(this.$t('settings.GMS.publish-location.updated'))
this.selectedOption = option.value
this.$store.commit('gmsPublishLocation', option.value)
this.$emit('gmsPublishLocation', option.value)
} catch (error) {
this.toastError(error.message)
}
},
},
}
</script>
<style>
.user-gms-location-format > .dropdown,
.user-gms-location-format > .dropdown > .dropdown-toggle > ul.dropdown-menu {
width: 100%;
}
</style>

View File

@ -0,0 +1,81 @@
import { mount } from '@vue/test-utils'
import UserGMSNamingFormat from './UserGMSNamingFormat.vue'
import { toastErrorSpy } from '@test/testSetup'
const mockAPIcall = jest.fn()
const storeCommitMock = jest.fn()
const localVue = global.localVue
describe('UserGMSNamingFormat', () => {
let wrapper
beforeEach(() => {
wrapper = mount(UserGMSNamingFormat, {
mocks: {
$t: (key) => key, // Mocking the translation function
$store: {
state: {
gmsPublishName: null,
},
commit: storeCommitMock,
},
$apollo: {
mutate: mockAPIcall,
},
},
localVue,
propsData: {
selectedOption: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS',
},
})
})
afterEach(() => {
wrapper.destroy()
})
it('renders the correct dropdown options', () => {
const dropdownItems = wrapper.findAll('.dropdown-item')
expect(dropdownItems.length).toBe(5)
const labels = dropdownItems.wrappers.map((item) => item.text())
expect(labels).toEqual([
'settings.GMS.publish-name.alias-or-initials',
'settings.GMS.publish-name.initials',
'settings.GMS.publish-name.first',
'settings.GMS.publish-name.first-initial',
'settings.GMS.publish-name.name-full',
])
})
it('updates selected option on click', async () => {
const dropdownItem = wrapper.findAll('.dropdown-item').at(3) // Click the fourth item
await dropdownItem.trigger('click')
expect(wrapper.emitted().gmsPublishName).toBeTruthy()
expect(wrapper.emitted().gmsPublishName.length).toBe(1)
expect(wrapper.emitted().gmsPublishName[0]).toEqual(['GMS_PUBLISH_NAME_FIRST_INITIAL'])
})
it('does not update when clicking on already selected option', async () => {
const dropdownItem = wrapper.findAll('.dropdown-item').at(0) // Click the first item (which is already selected)
await dropdownItem.trigger('click')
expect(wrapper.emitted().gmsPublishName).toBeFalsy()
})
describe('update with error', () => {
beforeEach(async () => {
mockAPIcall.mockRejectedValue({
message: 'Ouch',
})
const dropdownItem = wrapper.findAll('.dropdown-item').at(2) // Click the third item
await dropdownItem.trigger('click')
})
it('toasts an error message', () => {
expect(toastErrorSpy).toBeCalledWith('Ouch')
})
})
})

View File

@ -0,0 +1,87 @@
<template>
<div class="user-gms-naming-format">
<b-dropdown v-model="selectedOption">
<template slot="button-content">{{ selectedOptionLabel }}</template>
<b-dropdown-item
v-for="option in dropdownOptions"
@click.prevent="update(option)"
:key="option.value"
:value="option.value"
:title="option.title"
>
{{ option.label }}
</b-dropdown-item>
</b-dropdown>
</div>
</template>
<script>
import { updateUserInfos } from '@/graphql/mutations'
export default {
name: 'UserGMSNamingFormat',
data() {
return {
selectedOption: this.$store.state.gmsPublishName ?? 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS',
dropdownOptions: [
{
label: this.$t('settings.GMS.publish-name.alias-or-initials'),
title: this.$t('settings.GMS.publish-name.alias-or-initials-tooltip'),
value: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS',
},
{
label: this.$t('settings.GMS.publish-name.initials'),
title: this.$t('settings.GMS.publish-name.initials-tooltip'),
value: 'GMS_PUBLISH_NAME_INITIALS',
},
{
label: this.$t('settings.GMS.publish-name.first'),
title: this.$t('settings.GMS.publish-name.first-tooltip'),
value: 'GMS_PUBLISH_NAME_FIRST',
},
{
label: this.$t('settings.GMS.publish-name.first-initial'),
title: this.$t('settings.GMS.publish-name.first-initial-tooltip'),
value: 'GMS_PUBLISH_NAME_FIRST_INITIAL',
},
{
label: this.$t('settings.GMS.publish-name.name-full'),
title: this.$t('settings.GMS.publish-name.name-full-tooltip'),
value: 'GMS_PUBLISH_NAME_FULL',
},
],
}
},
computed: {
selectedOptionLabel() {
return this.dropdownOptions.find((option) => option.value === this.selectedOption).label
},
},
methods: {
async update(option) {
if (option.value === this.selectedOption) {
return
}
try {
await this.$apollo.mutate({
mutation: updateUserInfos,
variables: {
gmsPublishName: option.value,
},
})
this.toastSuccess(this.$t('settings.GMS.publish-name.updated'))
this.selectedOption = option.value
this.$store.commit('gmsPublishName', option.value)
this.$emit('gmsPublishName', option.value)
} catch (error) {
this.toastError(error.message)
}
},
},
}
</script>
<style>
.user-gms-naming-format > .dropdown,
.user-gms-naming-format > .dropdown > .dropdown-toggle > ul.dropdown-menu {
width: 100%;
}
</style>

View File

@ -0,0 +1,45 @@
<template>
<div class="form-user-gms-switch">
<b-form-checkbox
test="BFormCheckbox"
v-model="gmsAllowed"
name="check-button"
switch
@change="onChange"
></b-form-checkbox>
</div>
</template>
<script>
import { updateUserInfos } from '@/graphql/mutations'
export default {
name: 'UserGMSSwitch',
data() {
return {
gmsAllowed: this.$store.state.gmsAllowed,
}
},
methods: {
async onChange() {
this.$apollo
.mutate({
mutation: updateUserInfos,
variables: {
gmsAllowed: this.gmsAllowed,
},
})
.then(() => {
this.$store.commit('gmsAllowed', this.gmsAllowed)
this.$emit('gmsAllowed', this.gmsAllowed)
this.toastSuccess(
this.gmsAllowed ? this.$t('settings.GMS.enabled') : this.$t('settings.GMS.disabled'),
)
})
.catch((error) => {
this.gmsAllowed = this.$store.state.gmsAllowed
this.toastError(error.message)
})
},
},
}
</script>

View File

@ -8,7 +8,7 @@ const constants = {
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
CONFIG_VERSION: {
DEFAULT: 'DEFAULT',
EXPECTED: 'v5.2024-01-08',
EXPECTED: 'v6.2024-02-27',
CURRENT: '',
},
}
@ -20,6 +20,10 @@ const version = {
BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT ?? '0000000').slice(0, 7),
}
const features = {
GMS_ACTIVE: process.env.GMS_ACTIVE ?? false,
}
const environment = {
NODE_ENV: process.env.NODE_ENV,
DEBUG: process.env.NODE_ENV !== 'production' ?? false,
@ -81,6 +85,7 @@ if (
const CONFIG = {
...constants,
...version,
...features,
...environment,
...endpoints,
...community,

View File

@ -35,9 +35,9 @@ export const updateUserInfos = gql`
$hideAmountGDD: Boolean
$hideAmountGDT: Boolean
$gmsAllowed: Boolean
$gmsPublishName: Int
$gmsPublishName: GmsPublishNameType
$gmsLocation: Location
$gmsPublishLocation: Int
$gmsPublishLocation: GmsPublishLocationType
) {
updateUserInfos(
firstName: $firstName
@ -172,6 +172,9 @@ export const login = gql`
klickTipp {
newsletterState
}
gmsAllowed
gmsPublishName
gmsPublishLocation
hasElopage
publisherId
roles

View File

@ -5,8 +5,10 @@
"1000thanks": "1000 Dank, weil du bei uns bist!",
"125": "125%",
"85": "85%",
"ExternServices": "Verknüpfte Dienste",
"GDD": "GDD",
"GDT": "GDT",
"GMS": "Gradido Karte",
"PersonalDetails": "Persönliche Angaben",
"advanced-calculation": "Vorausberechnung",
"asterisks": "****",
@ -290,6 +292,36 @@
},
"settings": {
"emailInfo": "Kann aktuell noch nicht geändert werden.",
"GMS": {
"disabled": "Daten werden nicht nach GMS exportiert",
"enabled": "Daten werden nach GMS exportiert",
"location": {
"label": "Positionsbestimmung",
"button": "Klick mich!"
},
"location-format": "Positionstyp",
"naming-format": "Namensformat im GMS",
"publish-location": {
"exact": "Genaue Position",
"approximate": "Ungefähre Position",
"random": "Zufallsposition",
"updated": "Positionstyp für GMS aktualisiert"
},
"publish-name": {
"alias-or-initials": "Benutzername oder Initialen",
"alias-or-initials-tooltip": "Benutzername, falls vorhanden, oder die Initialen von Vorname und Nachname",
"first": "Vorname",
"first-tooltip": "Nur der Vornamen",
"first-initial": "Vorname und Initiale",
"first-initial-tooltip": "Vornamen plus Anfangsbuchstabe des Nachnamens",
"initials": "Initialen",
"initials-tooltip": "Initialen von Vor- und Nachname unabhängig von der Existenz des Benutzernamens",
"name-full": "Ganzer Name",
"name-full-tooltip": "Vollständiger Name: Vorname plus Nachname",
"updated": "Namensformat für GMS aktualisiert"
},
"switch": "Erlaubnis Daten nach GMS zu exportieren."
},
"hideAmountGDD": "Dein GDD Betrag ist versteckt.",
"hideAmountGDT": "Dein GDT Betrag ist versteckt.",
"info": "Transaktionen können nun per Benutzername oder E-Mail-Adresse getätigt werden.",

View File

@ -5,8 +5,10 @@
"1000thanks": "1000 thanks for being with us!",
"125": "125%",
"85": "85%",
"ExternServices": "Extern Services",
"GDD": "GDD",
"GDT": "GDT",
"GMS": "Gradido Map",
"PersonalDetails": "Personal details",
"advanced-calculation": "Advanced calculation",
"asterisks": "****",
@ -290,6 +292,36 @@
},
"settings": {
"emailInfo": "Cannot be changed at this time.",
"GMS": {
"disabled": "Data not exported to GMS",
"enabled": "Data exported to GMS",
"location": {
"label": "pinpoint location",
"button": "click me!"
},
"location-format": "location type",
"naming-format": "Format of name in GMS",
"publish-location": {
"exact": "exact position",
"approximate": "approximate position",
"random": "random position",
"updated": "format of location for GMS updated"
},
"publish-name": {
"alias-or-initials": "Username or initials",
"alias-or-initials-tooltip": "username if exists or Initials of firstname and lastname",
"first": "firstname",
"first-tooltip": "the firstname only",
"first-initial": "firstname and initial",
"first-initial-tooltip": "firstname plus initial of lastname",
"initials": "Initials of firstname and lastname independent if username exists",
"initials-tooltip": "Initials of firstname and lastname independent if username exists",
"name-full": "fullname",
"name-full-tooltip": "fullname: firstname plus lastname",
"updated": "format of name for GMS updated"
},
"switch": "Allow data export to GMS"
},
"hideAmountGDD": "Your GDD amount is hidden.",
"hideAmountGDT": "Your GDT amount is hidden.",
"info": "Transactions can now be made by username or email address.",

View File

@ -1,81 +1,129 @@
<template>
<div class="card bg-white gradido-border-radius appBoxShadow p-4 mt--3">
<div class="h2">{{ $t('PersonalDetails') }}</div>
<div class="my-4 text-small">
{{ $t('settings.info') }}
</div>
<b-row>
<b-col cols="12" md="6" lg="6">
<user-name />
</b-col>
<b-col cols="12" md="6" lg="6">
<b-form-group :label="$t('form.email')" :description="$t('settings.emailInfo')">
<b-form-input v-model="email" readonly></b-form-input>
</b-form-group>
</b-col>
</b-row>
<hr />
<b-form>
<b-row class="mt-3">
<b-col cols="12" md="6" lg="6">
<label>{{ $t('form.firstname') }}</label>
<b-form-input
v-model="firstName"
:placeholder="$t('settings.name.enterFirstname')"
data-test="firstname"
trim
></b-form-input>
</b-col>
<b-col cols="12" md="6" lg="6">
<label>{{ $t('form.lastname') }}</label>
<b-form-input
v-model="lastName"
:placeholder="$t('settings.name.enterLastname')"
data-test="lastname"
trim
></b-form-input>
</b-col>
</b-row>
<div v-if="!isDisabled" class="mt-4 pt-4 text-center">
<b-button
type="submit"
variant="primary"
@click.prevent="onSubmit"
data-test="submit-userdata"
>
{{ $t('form.save') }}
</b-button>
</div>
</b-form>
<hr />
<b-row>
<b-col cols="12" md="6" lg="6">{{ $t('language') }}</b-col>
<b-col cols="12" md="6" lg="6" class="text-right">
<user-language />
</b-col>
</b-row>
<hr />
<div class="mt-5">{{ $t('form.password') }}</div>
<user-password />
<hr />
<b-row class="mb-5">
<b-col cols="12" md="6" lg="6">
{{ $t('settings.newsletter.newsletter') }}
<div class="text-small">
{{
newsletterState
? $t('settings.newsletter.newsletterTrue')
: $t('settings.newsletter.newsletterFalse')
}}
<b-tabs content-class="mt-3">
<b-tab :title="$t('PersonalDetails')" active>
<div class="h2">{{ $t('PersonalDetails') }}</div>
<div class="my-4 text-small">
{{ $t('settings.info') }}
</div>
</b-col>
<b-col cols="12" md="6" lg="6" class="text-right">
<user-newsletter />
</b-col>
</b-row>
<b-row>
<b-col cols="12" md="6" lg="6">
<user-name />
</b-col>
<b-col cols="12" md="6" lg="6">
<b-form-group :label="$t('form.email')" :description="$t('settings.emailInfo')">
<b-form-input v-model="email" readonly></b-form-input>
</b-form-group>
</b-col>
</b-row>
<hr />
<b-form>
<b-row class="mt-3">
<b-col cols="12" md="6" lg="6">
<label>{{ $t('form.firstname') }}</label>
<b-form-input
v-model="firstName"
:placeholder="$t('settings.name.enterFirstname')"
data-test="firstname"
trim
></b-form-input>
</b-col>
<b-col cols="12" md="6" lg="6">
<label>{{ $t('form.lastname') }}</label>
<b-form-input
v-model="lastName"
:placeholder="$t('settings.name.enterLastname')"
data-test="lastname"
trim
></b-form-input>
</b-col>
</b-row>
<div v-if="!isDisabled" class="mt-4 pt-4 text-center">
<b-button
type="submit"
variant="primary"
@click.prevent="onSubmit"
data-test="submit-userdata"
>
{{ $t('form.save') }}
</b-button>
</div>
</b-form>
<hr />
<b-row>
<b-col cols="12" md="6" lg="6">{{ $t('language') }}</b-col>
<b-col cols="12" md="6" lg="6" class="text-right">
<user-language />
</b-col>
</b-row>
<hr />
<div class="mt-5">{{ $t('form.password') }}</div>
<user-password />
<hr />
<b-row class="mb-5">
<b-col cols="12" md="6" lg="6">
{{ $t('settings.newsletter.newsletter') }}
<div class="text-small">
{{
newsletterState
? $t('settings.newsletter.newsletterTrue')
: $t('settings.newsletter.newsletterFalse')
}}
</div>
</b-col>
<b-col cols="12" md="6" lg="6" class="text-right">
<user-newsletter />
</b-col>
</b-row>
</b-tab>
<div v-if="isGMS">
<b-tab :title="$t('ExternServices')">
<div class="h2">{{ $t('ExternServices') }}</div>
<div class="h3">{{ $t('GMS') }}</div>
<b-row class="mb-3">
<b-col cols="12" md="6" lg="6">
{{ $t('settings.GMS.switch') }}
<div class="text-small">
{{ gmsAllowed ? $t('settings.GMS.enabled') : $t('settings.GMS.disabled') }}
</div>
</b-col>
<b-col cols="12" md="6" lg="6" class="text-right">
<user-g-m-s-switch @gmsAllowed="gmsStateSwitch" />
</b-col>
</b-row>
<div v-if="gmsAllowed">
<b-row class="mb-4">
<b-col cols="12" md="6" lg="6">
{{ $t('settings.GMS.naming-format') }}
</b-col>
<b-col cols="12" md="6" lg="6">
<user-g-m-s-naming-format />
</b-col>
</b-row>
<b-row class="mb-4">
<b-col cols="12" md="6" lg="6">
{{ $t('settings.GMS.location-format') }}
</b-col>
<b-col cols="12" md="6" lg="6">
<user-g-m-s-location-format />
</b-col>
</b-row>
<b-row class="mb-5">
<b-col cols="12" md="6" lg="6">
{{ $t('settings.GMS.location.label') }}
</b-col>
<b-col cols="12" md="6" lg="6">
<user-g-m-s-location />
</b-col>
</b-row>
</div>
</b-tab>
</div>
</b-tabs>
<!-- TODO<b-row>
<b-col cols="12" md="6" lg="6">{{ $t('settings.darkMode') }}</b-col>
<b-col cols="12" md="6" lg="6" class="text-right">
@ -85,15 +133,24 @@
</div>
</template>
<script>
import UserGMSSwitch from '@/components/UserSettings/UserGMSSwitch'
import UserGMSNamingFormat from '@/components/UserSettings/UserGMSNamingFormat'
import UserGMSLocationFormat from '@/components/UserSettings/UserGMSLocationFormat'
import UserGMSLocation from '@/components/UserSettings/UserGMSLocation'
import UserName from '@/components/UserSettings/UserName.vue'
import UserPassword from '@/components/UserSettings/UserPassword'
import UserLanguage from '@/components/LanguageSwitch2.vue'
import UserNewsletter from '@/components/UserSettings/UserNewsletter.vue'
import { updateUserInfos } from '@/graphql/mutations'
import CONFIG from '../config'
export default {
name: 'Profile',
components: {
UserGMSSwitch,
UserGMSNamingFormat,
UserGMSLocationFormat,
UserGMSLocation,
UserName,
UserPassword,
UserLanguage,
@ -106,7 +163,7 @@ export default {
data() {
const { state } = this.$store
const { darkMode, firstName, lastName, email, newsletterState } = state
const { darkMode, firstName, lastName, email, newsletterState, gmsAllowed } = state
return {
darkMode,
@ -115,6 +172,7 @@ export default {
lastName,
email,
newsletterState,
gmsAllowed,
mutation: '',
variables: {},
}
@ -125,6 +183,9 @@ export default {
const { firstName, lastName } = this.$store.state
return firstName === this.firstName && lastName === this.lastName
},
isGMS() {
return CONFIG.GMS_ACTIVE
},
},
// TODO: watch: {
// darkMode(val) {
@ -150,6 +211,9 @@ export default {
this.toastSuccess(this.$t('settings.name.change-success'))
} catch (error) {}
},
gmsStateSwitch(eventData) {
this.gmsAllowed = eventData
},
},
}
</script>

View File

@ -35,6 +35,15 @@ export const mutations = {
newsletterState: (state, newsletterState) => {
state.newsletterState = newsletterState
},
gmsAllowed: (state, gmsAllowed) => {
state.gmsAllowed = gmsAllowed
},
gmsPublishName: (state, gmsPublishName) => {
state.gmsPublishName = gmsPublishName
},
gmsPublishLocation: (state, gmsPublishLocation) => {
state.gmsPublishLocation = gmsPublishLocation
},
publisherId: (state, publisherId) => {
let pubId = parseInt(publisherId)
if (isNaN(pubId)) pubId = null
@ -71,6 +80,9 @@ export const actions = {
commit('firstName', data.firstName)
commit('lastName', data.lastName)
commit('newsletterState', data.klickTipp.newsletterState)
commit('gmsAllowed', data.gmsAllowed)
commit('gmsPublishName', data.gmsPublishName)
commit('gmsPublishLocation', data.gmsPublishLocation)
commit('hasElopage', data.hasElopage)
commit('publisherId', data.publisherId)
commit('roles', data.roles)
@ -85,6 +97,9 @@ export const actions = {
commit('firstName', '')
commit('lastName', '')
commit('newsletterState', null)
commit('gmsAllowed', null)
commit('gmsPublishName', null)
commit('gmsPublishLocation', null)
commit('hasElopage', false)
commit('publisherId', null)
commit('roles', null)
@ -117,6 +132,9 @@ try {
tokenTime: null,
roles: [],
newsletterState: null,
gmsAllowed: null,
gmsPublishName: null,
gmsPublishLocation: null,
hasElopage: false,
publisherId: null,
hideAmountGDD: null,
@ -126,7 +144,7 @@ try {
redirectPath: '/overview',
},
getters: {},
// Syncronous mutation of the state
// Synchronous mutation of the state
mutations,
actions,
})

View File

@ -28,6 +28,9 @@ const {
lastName,
username,
newsletterState,
gmsAllowed,
gmsPublishName,
gmsPublishLocation,
publisherId,
roles,
hasElopage,
@ -122,6 +125,30 @@ describe('Vuex store', () => {
})
})
describe('gmsAllowed', () => {
it('sets the state of gmsAllowed', () => {
const state = { gmsAllowed: null }
gmsAllowed(state, true)
expect(state.gmsAllowed).toEqual(true)
})
})
describe('gmsPublishName', () => {
it('sets gmsPublishName', () => {
const state = { gmsPublishName: null }
gmsPublishName(state, 'GMS_PUBLISH_NAME_INITIALS')
expect(state.gmsPublishName).toEqual('GMS_PUBLISH_NAME_INITIALS')
})
})
describe('gmsPublishLocation', () => {
it('sets gmsPublishLocation', () => {
const state = { gmsPublishLocation: null }
gmsPublishLocation(state, 'GMS_LOCATION_TYPE_APPROXIMATE')
expect(state.gmsPublishLocation).toEqual('GMS_LOCATION_TYPE_APPROXIMATE')
})
})
describe('publisherId', () => {
it('sets the state of publisherId', () => {
const state = {}
@ -190,6 +217,9 @@ describe('Vuex store', () => {
klickTipp: {
newsletterState: true,
},
gmsAllowed: true,
gmsPublishName: 'GMS_PUBLISH_NAME_FULL',
gmsPublishLocation: 'GMS_LOCATION_TYPE_EXACT',
hasElopage: false,
publisherId: 1234,
roles: ['admin'],
@ -197,9 +227,9 @@ describe('Vuex store', () => {
hideAmountGDT: true,
}
it('calls eleven commits', () => {
it('calls fifteen commits', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenCalledTimes(12)
expect(commit).toHaveBeenCalledTimes(15)
})
it('commits gradidoID', () => {
@ -232,29 +262,44 @@ describe('Vuex store', () => {
expect(commit).toHaveBeenNthCalledWith(6, 'newsletterState', true)
})
it('commits gmsAllowed', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(7, 'gmsAllowed', true)
})
it('commits gmsPublishName', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(8, 'gmsPublishName', 'GMS_PUBLISH_NAME_FULL')
})
it('commits gmsPublishLocation', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(9, 'gmsPublishLocation', 'GMS_LOCATION_TYPE_EXACT')
})
it('commits hasElopage', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(7, 'hasElopage', false)
expect(commit).toHaveBeenNthCalledWith(10, 'hasElopage', false)
})
it('commits publisherId', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(8, 'publisherId', 1234)
expect(commit).toHaveBeenNthCalledWith(11, 'publisherId', 1234)
})
it('commits roles', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(9, 'roles', ['admin'])
expect(commit).toHaveBeenNthCalledWith(12, 'roles', ['admin'])
})
it('commits hideAmountGDD', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(10, 'hideAmountGDD', false)
expect(commit).toHaveBeenNthCalledWith(13, 'hideAmountGDD', false)
})
it('commits hideAmountGDT', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(11, 'hideAmountGDT', true)
expect(commit).toHaveBeenNthCalledWith(14, 'hideAmountGDT', true)
})
})
@ -262,9 +307,9 @@ describe('Vuex store', () => {
const commit = jest.fn()
const state = {}
it('calls twelve commits', () => {
it('calls seventeen commits', () => {
logout({ commit, state })
expect(commit).toHaveBeenCalledTimes(14)
expect(commit).toHaveBeenCalledTimes(17)
})
it('commits token', () => {
@ -297,34 +342,49 @@ describe('Vuex store', () => {
expect(commit).toHaveBeenNthCalledWith(6, 'newsletterState', null)
})
it('commits gmsAllowed', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(7, 'gmsAllowed', null)
})
it('commits gmsPublishName', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(8, 'gmsPublishName', null)
})
it('commits gmsPublishLocation', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(9, 'gmsPublishLocation', null)
})
it('commits hasElopage', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(7, 'hasElopage', false)
expect(commit).toHaveBeenNthCalledWith(10, 'hasElopage', false)
})
it('commits publisherId', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(8, 'publisherId', null)
expect(commit).toHaveBeenNthCalledWith(11, 'publisherId', null)
})
it('commits roles', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(9, 'roles', null)
expect(commit).toHaveBeenNthCalledWith(12, 'roles', null)
})
it('commits hideAmountGDD', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(10, 'hideAmountGDD', false)
expect(commit).toHaveBeenNthCalledWith(13, 'hideAmountGDD', false)
})
it('commits hideAmountGDT', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(11, 'hideAmountGDT', true)
expect(commit).toHaveBeenNthCalledWith(14, 'hideAmountGDT', true)
})
it('commits email', () => {
logout({ commit, state })
expect(commit).toHaveBeenNthCalledWith(12, 'email', '')
expect(commit).toHaveBeenNthCalledWith(15, 'email', '')
})
// how to get this working?