-
-
@@ -47,14 +40,6 @@
:label="$t('settings.data.labelName')"
:placeholder="$t('settings.data.namePlaceholder')"
/>
-
-
-
- Your e-mail address:
- {{ this.sliderData.collectedInputData.email }}
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -130,15 +101,17 @@
import { VERSION } from '~/constants/terms-and-conditions-version.js'
import links from '~/constants/links'
import emails from '~/constants/emails'
-import PasswordStrength from '../Password/Strength'
+import PasswordStrength from '~/components/Password/Strength'
+import EmailDisplayAndVerify from './EmailDisplayAndVerify'
import { SweetalertIcon } from 'vue-sweetalert-icons'
import PasswordForm from '~/components/utils/PasswordFormHelper'
import { SignupVerificationMutation } from '~/graphql/Registration.js'
export default {
- name: 'RegistrationItemCreateUserAccount',
+ name: 'RegistrationSlideCreate',
components: {
PasswordStrength,
+ EmailDisplayAndVerify,
SweetalertIcon,
},
props: {
@@ -151,7 +124,6 @@ export default {
supportEmail: emails.SUPPORT,
formData: {
name: '',
- about: '',
...passwordForm.formData,
},
formSchema: {
@@ -160,32 +132,23 @@ export default {
required: true,
min: 3,
},
- about: {
- type: 'string',
- required: false,
- },
...passwordForm.formSchema,
},
- response: null, // Wolle
+ response: null,
// TODO: Our styleguide does not support checkmarks.
// Integrate termsAndConditionsConfirmed into `this.formData` once we
// have checkmarks available.
termsAndConditionsConfirmed: false,
- dataPrivacy: false,
- minimumAge: false,
- noCommercial: false,
- noPolitical: false,
+ recieveCommunicationAsEmailsEtcConfirmed: false,
}
},
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the entire view has been rendered
+
this.formData.name = this.sliderData.collectedInputData.name
? this.sliderData.collectedInputData.name
: ''
- this.formData.about = this.sliderData.collectedInputData.about
- ? this.sliderData.collectedInputData.about
- : ''
this.formData.password = this.sliderData.collectedInputData.password
? this.sliderData.collectedInputData.password
: ''
@@ -196,17 +159,9 @@ export default {
.termsAndConditionsConfirmed
? this.sliderData.collectedInputData.termsAndConditionsConfirmed
: false
- this.dataPrivacy = this.sliderData.collectedInputData.dataPrivacy
- ? this.sliderData.collectedInputData.dataPrivacy
- : false
- this.minimumAge = this.sliderData.collectedInputData.minimumAge
- ? this.sliderData.collectedInputData.minimumAge
- : false
- this.noCommercial = this.sliderData.collectedInputData.noCommercial
- ? this.sliderData.collectedInputData.noCommercial
- : false
- this.noPolitical = this.sliderData.collectedInputData.noPolitical
- ? this.sliderData.collectedInputData.noPolitical
+ this.recieveCommunicationAsEmailsEtcConfirmed = this.sliderData.collectedInputData
+ .recieveCommunicationAsEmailsEtcConfirmed
+ ? this.sliderData.collectedInputData.recieveCommunicationAsEmailsEtcConfirmed
: false
this.sendValidation()
@@ -222,10 +177,7 @@ export default {
this.formData.password.length >= 1 &&
this.formData.password === this.formData.passwordConfirmation &&
this.termsAndConditionsConfirmed &&
- this.dataPrivacy &&
- this.minimumAge &&
- this.noCommercial &&
- this.noPolitical
+ this.recieveCommunicationAsEmailsEtcConfirmed
)
},
},
@@ -233,41 +185,22 @@ export default {
termsAndConditionsConfirmed() {
this.sendValidation()
},
- dataPrivacy() {
- this.sendValidation()
- },
- minimumAge() {
- this.sendValidation()
- },
- noCommercial() {
- this.sendValidation()
- },
- noPolitical() {
+ recieveCommunicationAsEmailsEtcConfirmed() {
this.sendValidation()
},
},
methods: {
sendValidation() {
- const { name, about, password, passwordConfirmation } = this.formData
- const {
- termsAndConditionsConfirmed,
- dataPrivacy,
- minimumAge,
- noCommercial,
- noPolitical,
- } = this
+ const { name, password, passwordConfirmation } = this.formData
+ const { termsAndConditionsConfirmed, recieveCommunicationAsEmailsEtcConfirmed } = this
this.sliderData.setSliderValuesCallback(this.validInput, {
collectedInputData: {
name,
- about,
password,
passwordConfirmation,
termsAndConditionsConfirmed,
- dataPrivacy,
- minimumAge,
- noCommercial,
- noPolitical,
+ recieveCommunicationAsEmailsEtcConfirmed,
},
})
},
@@ -278,31 +211,39 @@ export default {
this.sendValidation()
},
async submit() {
- const { name, password, about } = this.formData
- const { email, nonce } = this.sliderData.collectedInputData
+ const { name, password } = this.formData
+ const { email, inviteCode = null, nonce } = this.sliderData.collectedInputData
const termsAndConditionsAgreedVersion = VERSION
const locale = this.$i18n.locale()
try {
+ this.sliderData.setSliderValuesCallback(null, {
+ sliderSettings: { buttonLoading: true },
+ })
await this.$apollo.mutate({
mutation: SignupVerificationMutation,
variables: {
name,
password,
- about,
email,
+ inviteCode,
nonce,
termsAndConditionsAgreedVersion,
locale,
},
})
this.response = 'success'
- // Wolle setTimeout(() => {
- // this.$emit('userCreated', {
- // email,
- // password,
- // })
- // }, 3000)
+ setTimeout(async () => {
+ await this.$store.dispatch('auth/login', { email, password })
+ this.$toast.success(this.$t('login.success'))
+ this.$router.push('/')
+ this.sliderData.setSliderValuesCallback(null, {
+ sliderSettings: { buttonLoading: false },
+ })
+ }, 3000)
} catch (err) {
+ this.sliderData.setSliderValuesCallback(null, {
+ sliderSettings: { buttonLoading: false },
+ })
this.response = 'error'
}
},
diff --git a/webapp/components/Registration/RegistrationSlideEmail.vue b/webapp/components/Registration/RegistrationSlideEmail.vue
new file mode 100644
index 000000000..5289248cc
--- /dev/null
+++ b/webapp/components/Registration/RegistrationSlideEmail.vue
@@ -0,0 +1,208 @@
+
+
+
+ {{ $t('components.registration.signup.form.description') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp/components/Registration/RegistrationItemEnterInvite.vue b/webapp/components/Registration/RegistrationSlideInvite.vue
similarity index 54%
rename from webapp/components/Registration/RegistrationItemEnterInvite.vue
rename to webapp/components/Registration/RegistrationSlideInvite.vue
index b52704224..5a3aee777 100644
--- a/webapp/components/Registration/RegistrationItemEnterInvite.vue
+++ b/webapp/components/Registration/RegistrationSlideInvite.vue
@@ -7,14 +7,14 @@
@input-valid="handleInputValid"
>
- {{ $t('components.enter-invite.form.description') }}
+ {{ $t('components.registration.invite-code.form.description') }}
@@ -29,7 +29,7 @@ export const isValidInviteCodeQuery = gql`
}
`
export default {
- name: 'RegistrationItemEnterInvite',
+ name: 'RegistrationSlideInvite',
props: {
sliderData: { type: Object, required: true },
},
@@ -41,17 +41,19 @@ export default {
formSchema: {
inviteCode: {
type: 'string',
- // Wolle min: 6,
- // max: 6,
+ min: 6,
+ max: 6,
required: true,
- message: this.$t('components.enter-invite.form.validations.length'),
+ message: this.$t('components.registration.invite-code.form.validations.length'),
},
},
+ dbRequestInProgress: false,
}
},
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the entire view has been rendered
+
this.formData.inviteCode = this.sliderData.collectedInputData.inviteCode
? this.sliderData.collectedInputData.inviteCode
: ''
@@ -74,12 +76,14 @@ export default {
async sendValidation() {
const { inviteCode } = this.formData
+ this.sliderData.setSliderValuesCallback(null, { collectedInputData: { inviteCode } })
+
let dbValidated = false
if (this.validInput) {
await this.handleSubmitVerify()
dbValidated = this.sliderData.sliders[this.sliderIndex].data.response.isValidInviteCode
}
- this.sliderData.setSliderValuesCallback(dbValidated, { collectedInputData: { inviteCode } })
+ this.sliderData.setSliderValuesCallback(dbValidated)
},
async handleInput() {
this.sendValidation()
@@ -87,45 +91,53 @@ export default {
async handleInputValid() {
this.sendValidation()
},
+ isVariablesRequested(variables) {
+ return (
+ this.sliderData.sliders[this.sliderIndex].data.request &&
+ this.sliderData.sliders[this.sliderIndex].data.request.variables &&
+ this.sliderData.sliders[this.sliderIndex].data.request.variables.code === variables.code
+ )
+ },
async handleSubmitVerify() {
- const { inviteCode } = this.formData
+ const { inviteCode } = this.sliderData.collectedInputData
const variables = { code: inviteCode }
- if (
- !this.sliderData.sliders[this.sliderIndex].data.request ||
- (this.sliderData.sliders[this.sliderIndex].data.request &&
- (!this.sliderData.sliders[this.sliderIndex].data.request.variables ||
- (this.sliderData.sliders[this.sliderIndex].data.request.variables &&
- !this.sliderData.sliders[this.sliderIndex].data.request.variables === variables)))
- ) {
- this.sliderData.setSliderValuesCallback(
- this.sliderData.sliders[this.sliderIndex].validated,
- { sliderData: { request: { variables }, response: null } },
- )
-
+ if (!this.isVariablesRequested(variables) && !this.dbRequestInProgress) {
try {
- const response = await this.$apollo.query({ query: isValidInviteCodeQuery, variables })
- this.sliderData.setSliderValuesCallback(
- this.sliderData.sliders[this.sliderIndex].validated,
- { sliderData: { response: response.data } },
- )
+ this.dbRequestInProgress = true
- if (
- this.sliderData.sliders[this.sliderIndex].data.response &&
- this.sliderData.sliders[this.sliderIndex].data.response.isValidInviteCode
- ) {
- this.$toast.success(
- this.$t('components.registration.invite-code.form.success', { inviteCode }),
- )
+ const response = await this.$apollo.query({ query: isValidInviteCodeQuery, variables })
+ this.sliderData.setSliderValuesCallback(null, {
+ sliderData: {
+ request: { variables },
+ response: response.data,
+ },
+ })
+
+ if (this.sliderData.sliders[this.sliderIndex].data.response) {
+ if (this.sliderData.sliders[this.sliderIndex].data.response.isValidInviteCode) {
+ this.$toast.success(
+ this.$t('components.registration.invite-code.form.validations.success', {
+ inviteCode,
+ }),
+ )
+ } else {
+ this.$toast.error(
+ this.$t('components.registration.invite-code.form.validations.error', {
+ inviteCode,
+ }),
+ )
+ }
}
} catch (err) {
- this.sliderData.setSliderValuesCallback(
- this.sliderData.sliders[this.sliderIndex].validated,
- { sliderData: { response: { isValidInviteCode: false } } },
- )
+ this.sliderData.setSliderValuesCallback(false, {
+ sliderData: { response: { isValidInviteCode: false } },
+ })
const { message } = err
this.$toast.error(message)
+ } finally {
+ this.dbRequestInProgress = false
}
}
},
diff --git a/webapp/components/Registration/RegistrationSlideNoPublic.vue b/webapp/components/Registration/RegistrationSlideNoPublic.vue
new file mode 100644
index 000000000..1d26cc8e2
--- /dev/null
+++ b/webapp/components/Registration/RegistrationSlideNoPublic.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
diff --git a/webapp/components/Registration/RegistrationSlideNonce.vue b/webapp/components/Registration/RegistrationSlideNonce.vue
new file mode 100644
index 000000000..40ccd10ad
--- /dev/null
+++ b/webapp/components/Registration/RegistrationSlideNonce.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+ {{ $t('components.registration.email-nonce.form.description') }}
+
+
+
+
+
+
+
+
diff --git a/webapp/components/Registration/RegistrationSlider.story.js b/webapp/components/Registration/RegistrationSlider.story.js
index fc6dd3e32..9fb1c347f 100644
--- a/webapp/components/Registration/RegistrationSlider.story.js
+++ b/webapp/components/Registration/RegistrationSlider.story.js
@@ -1,8 +1,10 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
-import RegistrationSlider from './RegistrationSlider.vue'
+import { action } from '@storybook/addon-actions'
+import Vuex from 'vuex'
import helpers from '~/storybook/helpers'
import Vue from 'vue'
+import RegistrationSlider from './RegistrationSlider.vue'
const plugins = [
(app = {}) => {
@@ -14,11 +16,8 @@ const plugins = [
if (JSON.stringify(data).includes('Signup')) {
return { data: { Signup: { email: data.variables.email } } }
}
- if (JSON.stringify(data).includes('SignupByInvitation')) {
- return { data: { SignupByInvitation: { email: data.variables.email } } }
- }
if (JSON.stringify(data).includes('SignupVerification')) {
- return { data: { SignupByInvitation: { ...data.variables } } }
+ return { data: { SignupVerification: { ...data.variables } } }
}
throw new Error(`Mutation name not found!`)
},
@@ -26,6 +25,9 @@ const plugins = [
if (JSON.stringify(data).includes('isValidInviteCode')) {
return { data: { isValidInviteCode: true } }
}
+ if (JSON.stringify(data).includes('VerifyNonce')) {
+ return { data: { VerifyNonce: true } }
+ }
throw new Error(`Query name not found!`)
},
}
@@ -35,12 +37,51 @@ const plugins = [
]
helpers.init({ plugins })
+const createStore = ({ loginSuccess }) => {
+ return new Vuex.Store({
+ modules: {
+ auth: {
+ namespaced: true,
+ state: () => ({
+ pending: false,
+ }),
+ mutations: {
+ SET_PENDING(state, pending) {
+ state.pending = pending
+ },
+ },
+ getters: {
+ pending(state) {
+ return !!state.pending
+ },
+ },
+ actions: {
+ async login({ commit, dispatch }, args) {
+ action('Vuex action `auth/login`')(args)
+ return new Promise((resolve, reject) => {
+ commit('SET_PENDING', true)
+ setTimeout(() => {
+ commit('SET_PENDING', false)
+ if (loginSuccess) {
+ resolve(loginSuccess)
+ } else {
+ reject(new Error('Login unsuccessful'))
+ }
+ }, 1000)
+ })
+ },
+ },
+ },
+ },
+ })
+}
+
storiesOf('RegistrationSlider', module)
.addDecorator(withA11y)
.addDecorator(helpers.layout)
.add('invite-code empty', () => ({
components: { RegistrationSlider },
- store: helpers.store,
+ store: createStore({ loginSuccess: true }),
data: () => ({}),
template: `
@@ -48,23 +89,19 @@ storiesOf('RegistrationSlider', module)
}))
.add('invite-code with data', () => ({
components: { RegistrationSlider },
- store: helpers.store,
+ store: createStore({ loginSuccess: true }),
data: () => ({
overwriteSliderData: {
collectedInputData: {
- inviteCode: 'IN1T6Y',
+ inviteCode: 'INZTBY',
email: 'wolle.huss@pjannto.com',
emailSend: false,
- nonce: 'NTRSCZ',
+ nonce: '47539',
name: 'Wolle',
password: 'Hello',
passwordConfirmation: 'Hello',
- about: `Hey`,
termsAndConditionsConfirmed: true,
- dataPrivacy: true,
- minimumAge: true,
- noCommercial: true,
- noPolitical: true,
+ recieveCommunicationAsEmailsEtcConfirmed: true,
},
},
}),
@@ -74,7 +111,7 @@ storiesOf('RegistrationSlider', module)
}))
.add('public-registration empty', () => ({
components: { RegistrationSlider },
- store: helpers.store,
+ store: createStore({ loginSuccess: true }),
data: () => ({}),
template: `
@@ -82,23 +119,19 @@ storiesOf('RegistrationSlider', module)
}))
.add('public-registration with data', () => ({
components: { RegistrationSlider },
- store: helpers.store,
+ store: createStore({ loginSuccess: true }),
data: () => ({
overwriteSliderData: {
collectedInputData: {
inviteCode: null,
email: 'wolle.huss@pjannto.com',
emailSend: false,
- nonce: 'NTRSCZ',
+ nonce: '47539',
name: 'Wolle',
password: 'Hello',
passwordConfirmation: 'Hello',
- about: `Hey`,
termsAndConditionsConfirmed: true,
- dataPrivacy: true,
- minimumAge: true,
- noCommercial: true,
- noPolitical: true,
+ recieveCommunicationAsEmailsEtcConfirmed: true,
},
},
}),
@@ -108,7 +141,7 @@ storiesOf('RegistrationSlider', module)
}))
.add('invite-mail empty', () => ({
components: { RegistrationSlider },
- store: helpers.store,
+ store: createStore({ loginSuccess: true }),
data: () => ({
overwriteSliderData: {
collectedInputData: {
@@ -119,12 +152,8 @@ storiesOf('RegistrationSlider', module)
name: null,
password: null,
passwordConfirmation: null,
- about: null,
termsAndConditionsConfirmed: null,
- dataPrivacy: null,
- minimumAge: null,
- noCommercial: null,
- noPolitical: null,
+ recieveCommunicationAsEmailsEtcConfirmed: null,
},
},
}),
@@ -134,23 +163,19 @@ storiesOf('RegistrationSlider', module)
}))
.add('invite-mail with data', () => ({
components: { RegistrationSlider },
- store: helpers.store,
+ store: createStore({ loginSuccess: true }),
data: () => ({
overwriteSliderData: {
collectedInputData: {
inviteCode: null,
email: 'wolle.huss@pjannto.com',
emailSend: true,
- nonce: 'NTRSCZ',
+ nonce: '47539',
name: 'Wolle',
password: 'Hello',
passwordConfirmation: 'Hello',
- about: `Hey`,
termsAndConditionsConfirmed: true,
- dataPrivacy: true,
- minimumAge: true,
- noCommercial: true,
- noPolitical: true,
+ recieveCommunicationAsEmailsEtcConfirmed: true,
},
},
}),
@@ -158,3 +183,11 @@ storiesOf('RegistrationSlider', module)
`,
}))
+ .add('no-public-registration', () => ({
+ components: { RegistrationSlider },
+ store: createStore({ loginSuccess: true }),
+ data: () => ({}),
+ template: `
+
+ `,
+ }))
diff --git a/webapp/components/Registration/RegistrationSlider.vue b/webapp/components/Registration/RegistrationSlider.vue
index e69231c78..b4a180ecf 100644
--- a/webapp/components/Registration/RegistrationSlider.vue
+++ b/webapp/components/Registration/RegistrationSlider.vue
@@ -8,37 +8,27 @@
-
-
- {{ $t('components.registration.signup.title', metadata) }}
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
+
+
-
+
-
+
{{ $t('site.back-to-login') }}
@@ -57,93 +47,113 @@ import links from '~/constants/links.js'
import metadata from '~/constants/metadata.js'
import ComponentSlider from '~/components/ComponentSlider/ComponentSlider'
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
-import RegistrationItemCreateUserAccount from './RegistrationItemCreateUserAccount'
-import RegistrationItemEnterEmail from '~/components/Registration/RegistrationItemEnterEmail'
-import RegistrationItemEnterInvite from './RegistrationItemEnterInvite'
-import RegistrationItemEnterNonce from './RegistrationItemEnterNonce'
+import RegistrationSlideCreate from './RegistrationSlideCreate'
+import RegistrationSlideEmail from './RegistrationSlideEmail'
+import RegistrationSlideInvite from './RegistrationSlideInvite'
+import RegistrationSlideNonce from './RegistrationSlideNonce'
+import RegistrationSlideNoPublic from './RegistrationSlideNoPublic'
export default {
name: 'RegistrationSlider',
components: {
ComponentSlider,
LocaleSwitch,
- RegistrationItemCreateUserAccount,
- RegistrationItemEnterEmail,
- RegistrationItemEnterInvite,
- RegistrationItemEnterNonce,
+ RegistrationSlideCreate,
+ RegistrationSlideEmail,
+ RegistrationSlideInvite,
+ RegistrationSlideNonce,
+ RegistrationSlideNoPublic,
},
props: {
registrationType: { type: String, required: true },
overwriteSliderData: { type: Object, default: () => {} },
},
data() {
- const slidersPortfolio = [
- {
+ const slidersPortfolio = {
+ noPublicRegistration: {
+ name: 'no-public-registration',
+ titleIdent: 'components.registration.no-public-registrstion.title',
+ validated: false,
+ data: { request: null, response: null },
+ button: {
+ titleIdent: 'site.back-to-login',
+ icon: null,
+ callback: this.buttonCallback,
+ sliderCallback: null, // optional set by slot
+ },
+ },
+ enterInvite: {
name: 'enter-invite',
- // title: this.$t('components.registration.create-user-account.title'),
- title: 'Invitation', // Wolle
+ titleIdent: { id: 'components.registration.signup.title', data: metadata },
validated: false,
data: { request: null, response: { isValidInviteCode: false } },
button: {
- title: 'Next', // Wolle
+ titleIdent: 'components.registration.invite-code.buttonTitle',
icon: 'arrow-right',
callback: this.buttonCallback,
sliderCallback: null, // optional set by slot
},
},
- {
+ enterEmail: {
name: 'enter-email',
- title: 'E-Mail', // Wolle
+ titleIdent: 'components.registration.email.title',
validated: false,
data: { request: null, response: null },
button: {
- title: '', // set by slider component
- icon: '', // set by slider component
+ titleIdent: 'components.registration.email.buttonTitle.send', // changed by slider component
+ icon: 'envelope', // changed by slider component
callback: this.buttonCallback,
sliderCallback: null, // optional set by slot
},
},
- {
+ enterNonce: {
name: 'enter-nonce',
- title: 'E-Mail Confirmation', // Wolle
+ titleIdent: 'components.registration.email-nonce.title',
validated: false,
- data: { request: null, response: null },
+ data: { request: null, response: { VerifyNonce: false } },
button: {
- title: 'Confirm', // Wolle
+ titleIdent: 'components.registration.email-nonce.buttonTitle',
icon: 'arrow-right',
callback: this.buttonCallback,
sliderCallback: null, // optional set by slot
},
},
- {
+ createUserAccount: {
name: 'create-user-account',
- title: this.$t('components.registration.create-user-account.title'),
+ titleIdent: 'components.registration.create-user-account.title',
validated: false,
data: { request: null, response: null },
button: {
- // title: this.$t('actions.save'), // Wolle
- title: 'Create', // Wolle
+ titleIdent: 'components.registration.create-user-account.buttonTitle',
icon: 'check',
+ loading: false,
callback: this.buttonCallback,
sliderCallback: null, // optional set by slot
},
},
- ]
+ }
let sliders = []
switch (this.registrationType) {
+ case 'no-public-registration':
+ sliders = [slidersPortfolio.noPublicRegistration]
+ break
case 'invite-code':
sliders = [
- slidersPortfolio[0],
- slidersPortfolio[1],
- slidersPortfolio[2],
- slidersPortfolio[3],
+ slidersPortfolio.enterInvite,
+ slidersPortfolio.enterEmail,
+ slidersPortfolio.enterNonce,
+ slidersPortfolio.createUserAccount,
]
break
case 'public-registration':
- sliders = [slidersPortfolio[1], slidersPortfolio[2], slidersPortfolio[3]]
+ sliders = [
+ slidersPortfolio.enterEmail,
+ slidersPortfolio.enterNonce,
+ slidersPortfolio.createUserAccount,
+ ]
break
case 'invite-mail':
- sliders = [slidersPortfolio[2], slidersPortfolio[3]]
+ sliders = [slidersPortfolio.enterNonce, slidersPortfolio.createUserAccount]
break
}
@@ -159,12 +169,8 @@ export default {
name: null,
password: null,
passwordConfirmation: null,
- about: null,
termsAndConditionsConfirmed: null,
- dataPrivacy: null,
- minimumAge: null,
- noCommercial: null,
- noPolitical: null,
+ recieveCommunicationAsEmailsEtcConfirmed: null,
},
sliderIndex: 0,
sliders: sliders,
@@ -180,11 +186,15 @@ export default {
},
},
methods: {
- setSliderValuesCallback(isValid, { collectedInputData, sliderData, sliderSettings }) {
+ setSliderValuesCallback(
+ isValid = null,
+ { collectedInputData, sliderData, sliderSettings } = {},
+ ) {
// all changes of 'this.sliders' has to be filled in from the top to be spread to the component slider and all slider components in the slot
- this.sliderData.sliders[this.sliderIndex].validated = isValid
-
+ if (isValid !== null) {
+ this.sliderData.sliders[this.sliderIndex].validated = isValid
+ }
if (collectedInputData) {
this.sliderData.collectedInputData = {
...this.sliderData.collectedInputData,
@@ -204,14 +214,17 @@ export default {
}
}
if (sliderSettings) {
- const { buttonTitle, buttonIcon, buttonSliderCallback } = sliderSettings
- if (buttonTitle) {
- this.sliderData.sliders[this.sliderIndex].button.title = buttonTitle
+ const { buttonTitleIdent, buttonIcon, buttonLoading, buttonSliderCallback } = sliderSettings
+ if (buttonTitleIdent !== undefined) {
+ this.sliderData.sliders[this.sliderIndex].button.titleIdent = buttonTitleIdent
}
- if (buttonIcon) {
+ if (buttonIcon !== undefined) {
this.sliderData.sliders[this.sliderIndex].button.icon = buttonIcon
}
- if (buttonSliderCallback) {
+ if (buttonLoading !== undefined) {
+ this.sliderData.sliders[this.sliderIndex].button.loading = buttonLoading
+ }
+ if (buttonSliderCallback !== undefined) {
this.sliderData.sliders[this.sliderIndex].button.sliderCallback = buttonSliderCallback
}
}
@@ -221,6 +234,10 @@ export default {
if (selectedIndex <= this.sliderIndex + 1 && selectedIndex < this.sliderData.sliders.length) {
this.sliderData.sliderIndex = selectedIndex
+
+ if (this.sliderData.sliders[this.sliderIndex].button.loading !== undefined) {
+ this.sliderData.sliders[this.sliderIndex].button.loading = false
+ }
}
},
buttonCallback(success) {
diff --git a/webapp/components/Registration/Signup.spec.js b/webapp/components/Registration/Signup.spec.js
index b8970b1dc..36b16903c 100644
--- a/webapp/components/Registration/Signup.spec.js
+++ b/webapp/components/Registration/Signup.spec.js
@@ -1,5 +1,5 @@
import { config, mount } from '@vue/test-utils'
-import Signup, { SignupMutation, SignupByInvitationMutation } from './Signup'
+import Signup, { SignupMutation } from './Signup'
const localVue = global.localVue
@@ -58,7 +58,8 @@ describe('Signup', () => {
it('delivers email to backend', () => {
const expected = expect.objectContaining({
- variables: { email: 'mAIL@exAMPLE.org', token: null },
+ mutation: SignupMutation,
+ variables: { email: 'mAIL@exAMPLE.org', inviteCode: null },
})
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
})
@@ -84,68 +85,5 @@ describe('Signup', () => {
})
})
})
-
- describe('with invitation code', () => {
- let action
- beforeEach(() => {
- propsData.token = '666777'
- action = async () => {
- wrapper = Wrapper()
- wrapper.find('input#email').setValue('mail@example.org')
- await wrapper.find('form').trigger('submit')
- await wrapper.html()
- }
- })
-
- describe('submit', () => {
- it('calls SignupByInvitation graphql mutation', async () => {
- await action()
- const expected = expect.objectContaining({ mutation: SignupByInvitationMutation })
- expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
- })
-
- it('delivers invitation token to backend', async () => {
- await action()
- const expected = expect.objectContaining({
- variables: { email: 'mail@example.org', token: '666777' },
- })
- expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
- })
-
- describe('in case a user account with the email already exists', () => {
- beforeEach(() => {
- mocks.$apollo.mutate = jest
- .fn()
- .mockRejectedValue(
- new Error('UserInputError: A user account with this email already exists.'),
- )
- })
-
- it('explains the error', async () => {
- await action()
- expect(mocks.$t).toHaveBeenCalledWith(
- 'components.registration.signup.form.errors.email-exists',
- )
- })
- })
-
- describe('in case the invitation code was incorrect', () => {
- beforeEach(() => {
- mocks.$apollo.mutate = jest
- .fn()
- .mockRejectedValue(
- new Error('UserInputError: Invitation code already used or does not exist.'),
- )
- })
-
- it('explains the error', async () => {
- await action()
- expect(mocks.$t).toHaveBeenCalledWith(
- 'components.registration.signup.form.errors.invalid-invitation-token',
- )
- })
- })
- })
- })
})
})
diff --git a/webapp/components/Registration/Signup.vue b/webapp/components/Registration/Signup.vue
index 0a8bed612..86142c338 100644
--- a/webapp/components/Registration/Signup.vue
+++ b/webapp/components/Registration/Signup.vue
@@ -14,9 +14,6 @@
: $t('components.registration.signup.title', metadata)
}}
-
-
-
{{
@@ -70,17 +67,11 @@
import gql from 'graphql-tag'
import metadata from '~/constants/metadata'
import { SweetalertIcon } from 'vue-sweetalert-icons'
+import translateErrorMessage from '~/components/utils/TranslateErrorMessage'
export const SignupMutation = gql`
- mutation($email: String!) {
- Signup(email: $email) {
- email
- }
- }
-`
-export const SignupByInvitationMutation = gql`
- mutation($email: String!, $token: String!) {
- SignupByInvitation(email: $email, token: $token) {
+ mutation($email: String!, $inviteCode: String) {
+ Signup(email: $email, inviteCode: $inviteCode) {
email
}
}
@@ -91,7 +82,6 @@ export default {
SweetalertIcon,
},
props: {
- token: { type: String, default: null },
invitation: { type: Boolean, default: false },
},
data() {
@@ -126,32 +116,28 @@ export default {
this.disabled = false
},
async handleSubmit() {
- const mutation = this.token ? SignupByInvitationMutation : SignupMutation
- const { token } = this
const { email } = this.formData
try {
- const response = await this.$apollo.mutate({ mutation, variables: { email, token } })
+ const response = await this.$apollo.mutate({
+ mutation: SignupMutation,
+ variables: { email, inviteCode: null },
+ })
this.data = response.data
setTimeout(() => {
this.$emit('submit', { email: this.data.Signup.email })
}, 3000)
} catch (err) {
- const { message } = err
- const mapping = {
- 'A user account with this email already exists': 'email-exists',
- 'Invitation code already used or does not exist': 'invalid-invitation-token',
- }
- for (const [pattern, key] of Object.entries(mapping)) {
- if (message.includes(pattern))
- this.error = {
- key,
- message: this.$t(`components.registration.signup.form.errors.${key}`),
- }
- }
- if (!this.error) {
- this.$toast.error(message)
- }
+ this.$toast.error(
+ translateErrorMessage(
+ err.message,
+ {
+ 'A user account with this email already exists':
+ 'components.registration.signup.form.errors.email-exists',
+ },
+ this.$t,
+ ),
+ )
}
},
},
diff --git a/webapp/components/utils/TranslateErrorMessage.js b/webapp/components/utils/TranslateErrorMessage.js
new file mode 100644
index 000000000..3597f3358
--- /dev/null
+++ b/webapp/components/utils/TranslateErrorMessage.js
@@ -0,0 +1,12 @@
+export default (message, mapping, translate) => {
+ let translatedMessage = null
+ for (const [pattern, ident] of Object.entries(mapping)) {
+ if (message.includes(pattern)) {
+ translatedMessage = translate(ident)
+ }
+ }
+ if (!translatedMessage) {
+ translatedMessage = message
+ }
+ return translatedMessage
+}
diff --git a/webapp/graphql/Registration.js b/webapp/graphql/Registration.js
index 873c855db..fcf9c52a7 100644
--- a/webapp/graphql/Registration.js
+++ b/webapp/graphql/Registration.js
@@ -4,6 +4,7 @@ export const SignupVerificationMutation = gql`
$nonce: String!
$name: String!
$email: String!
+ $inviteCode: String
$password: String!
$about: String
$termsAndConditionsAgreedVersion: String!
@@ -12,6 +13,7 @@ export const SignupVerificationMutation = gql`
SignupVerification(
nonce: $nonce
email: $email
+ inviteCode: $inviteCode
name: $name
password: $password
about: $about
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 429764741..a81764e82 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -120,26 +120,6 @@
"versus": "Versus"
},
"components": {
- "enter-invite": {
- "form": {
- "description": "Gib den Einladungs-Code ein, den du bekommen hast.",
- "invite-code": "Einladungs-Code eingeben",
- "next": "Weiter",
- "validations": {
- "length": "muss genau 6 Buchstaben lang sein"
- }
- }
- },
- "enter-nonce": {
- "form": {
- "description": "Öffne Dein E-Mail Postfach und gib den Code ein, den wir geschickt haben.",
- "next": "Weiter",
- "nonce": "Code eingeben",
- "validations": {
- "length": "muss genau 6 Buchstaben lang sein"
- }
- }
- },
"password-reset": {
"change-password": {
"error": "Passwort Änderung fehlgeschlagen. Möglicherweise falscher Sicherheitscode?",
@@ -157,33 +137,68 @@
},
"registration": {
"create-user-account": {
+ "buttonTitle": "Erstellen",
"error": "Es konnte kein Benutzerkonto erstellt werden!",
"help": "Vielleicht war der Bestätigungscode falsch oder abgelaufen? Wenn das Problem weiterhin besteht, schicke uns gerne eine E-Mail an:",
+ "recieveCommunicationAsEmailsEtcConfirmed": "Ich stimme auch dem Erhalt von E-Mails und anderen Formen der Kommunikation (z.B. Push-Benachrichtigungen) zu.",
"success": "Dein Benutzerkonto wurde erstellt!",
+ "termsAndCondsEtcConfirmed": "Ich habe folgendes gelesen, verstanden und stimme zu:",
"title": "Benutzerkonto anlegen"
},
"email": {
+ "buttonTitle": {
+ "resend": "Erneut senden",
+ "send": "Sende E-Mail",
+ "skipResend": "Nicht senden"
+ },
"form": {
+ "sendEmailAgain": "E-Mail erneut senden",
"success": "Verifikations-E-Mail gesendet an {email}!"
- }
+ },
+ "title": "E-Mail"
+ },
+ "email-display": {
+ "warningFormat": "⚠️ E-Mail hat ein ungültiges Format!",
+ "warningUndef": "⚠️ Keine E-Mail definiert!",
+ "yourEmail": "Deine E-Mail-Adresse:"
+ },
+ "email-nonce": {
+ "buttonTitle": "Bestätigen",
+ "form": {
+ "description": "Öffne Dein E-Mail Postfach und gib den Code ein, den wir geschickt haben.",
+ "next": "Weiter",
+ "nonce": "E-Mail-Code: 32143",
+ "validations": {
+ "error": "Ungültiger Bestätigungs-Code {nonce} für E-Mail {email}!",
+ "length": "muss genau 5 Buchstaben lang sein",
+ "success": "Gültiger Bestätigungs-Code {nonce} für E-Mail {email}!"
+ }
+ },
+ "title": "E-Mail Bestätigung"
},
"invite-code": {
+ "buttonTitle": "Weiter",
"form": {
- "success": "Gültiger Einladungs-Code {inviteCode}!"
+ "description": "Gib den Einladungs-Code ein, den du bekommen hast.",
+ "invite-code": "Einladungs-Code: ACJERB",
+ "next": "Weiter",
+ "validations": {
+ "error": "Ungültiger Einladungs-Code {inviteCode}!",
+ "length": "muss genau 6 Buchstaben lang sein",
+ "success": "Gültiger Einladungs-Code {inviteCode}!"
+ }
}
},
+ "no-public-registrstion": {
+ "title": "Keine öffentliche Registrierung möglich"
+ },
"signup": {
"form": {
"data-privacy": "Ich habe die Datenschutzerklärung gelesen und verstanden.",
"description": "Um loszulegen, kannst Du Dich hier kostenfrei registrieren:",
"errors": {
- "email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail-Adresse!",
- "invalid-invitation-token": "Es sieht so aus, als ob der Einladungscode schon eingelöst wurde. Jeder Code kann nur einmalig benutzt werden."
+ "email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail-Adresse!"
},
- "invitation-code": "Dein Einladungscode lautet: {code}",
- "minimum-age": "Ich bin 18 Jahre oder älter.",
- "no-commercial": "Ich habe keine kommerziellen Absichten und ich repräsentiere kein kommerzielles Unternehmen oder Organisation.",
- "no-political": "Ich bin nicht im Auftrag einer Partei oder politischen Organisation im Netzwerk.",
"submit": "Konto erstellen",
"success": "Eine E-Mail mit einem Link zum Abschließen Deiner Registrierung wurde an {email} geschickt",
"terms-and-condition": "Ich stimme den Nutzungsbedingungen zu."
@@ -786,9 +801,7 @@
}
},
"termsAndConditions": {
- "agree": "Ich stimme zu!",
"newTermsAndConditions": "Neue Nutzungsbedingungen",
- "termsAndConditionsConfirmed": "Ich habe die Nutzungsbedingungen durchgelesen und stimme ihnen zu.",
"termsAndConditionsNewConfirm": "Ich habe die neuen Nutzungsbedingungen durchgelesen und stimme zu.",
"termsAndConditionsNewConfirmText": "Bitte lies Dir die neuen Nutzungsbedingungen jetzt durch!"
},
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index a9454b5c2..df34e60c3 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -120,26 +120,6 @@
"versus": "Versus"
},
"components": {
- "enter-invite": {
- "form": {
- "description": "Enter the invitation code you received.",
- "invite-code": "Enter your invite code",
- "next": "Continue",
- "validations": {
- "length": "must be 6 characters long"
- }
- }
- },
- "enter-nonce": {
- "form": {
- "description": "Open your inbox and enter the code that we've sent to you.",
- "next": "Continue",
- "nonce": "Enter your code",
- "validations": {
- "length": "must be 6 characters long"
- }
- }
- },
"password-reset": {
"change-password": {
"error": "Changing your password failed. Maybe the security code was not correct?",
@@ -157,33 +137,68 @@
},
"registration": {
"create-user-account": {
+ "buttonTitle": "Create",
"error": "No user account could be created!",
"help": " Maybe the confirmation was invalid? In case of problems, feel free to ask for help by sending us a mail to:",
+ "recieveCommunicationAsEmailsEtcConfirmed": "I also agree to receive e-mails and other forms of communication (e.g. push notifications).",
"success": "Your account has been created!",
+ "termsAndCondsEtcConfirmed": "I have read, understand and agree to the following:",
"title": "Create user account"
},
"email": {
+ "buttonTitle": {
+ "resend": "Resend e-mail",
+ "send": "Send e-mail",
+ "skipResend": "Skip resend"
+ },
"form": {
+ "sendEmailAgain": "Send e-mail again",
"success": "Verification e-mail send to {email}!"
- }
+ },
+ "title": "E-Mail"
+ },
+ "email-display": {
+ "warningFormat": "⚠️ E-mail has wrong format!",
+ "warningUndef": "⚠️ No e-mail defined!",
+ "yourEmail": "Your e-mail address:"
+ },
+ "email-nonce": {
+ "buttonTitle": "Confirm",
+ "form": {
+ "description": "Open your inbox and enter the code that we've sent to you.",
+ "next": "Continue",
+ "nonce": "E-mail code: 32143",
+ "validations": {
+ "error": "Invalid verification code {nonce} for e-mail {email}!",
+ "length": "must be 5 characters long",
+ "success": "Valid verification code {nonce} for e-mail {email}!"
+ }
+ },
+ "title": "E-Mail Confirmation"
},
"invite-code": {
+ "buttonTitle": "Next",
"form": {
- "success": "Valid invite code {inviteCode}!"
+ "description": "Enter the invitation code you received.",
+ "invite-code": "Invite code: ACJERB",
+ "next": "Continue",
+ "validations": {
+ "error": "Invalid invite code {inviteCode}!",
+ "length": "must be 6 characters long",
+ "success": "Valid invite code {inviteCode}!"
+ }
}
},
+ "no-public-registrstion": {
+ "title": "No Public Registration"
+ },
"signup": {
"form": {
"data-privacy": "I have read and understood the privacy statement.",
"description": "To get started, you can register here for free:",
"errors": {
- "email-exists": "There is already a user account with this e-mail address!",
- "invalid-invitation-token": "It looks like as if the invitation has been used already. Invitation links can only be used once."
+ "email-exists": "There is already a user account with this e-mail address!"
},
- "invitation-code": "Your invitation code is: {code}",
- "minimum-age": "I'm 18 years or older.",
- "no-commercial": "I have no commercial interests and I am not representing a company or any other commercial organisation on the network.",
- "no-political": "I am not on behalf of a party or political organization in the network.",
"submit": "Create an account",
"success": "A mail with a link to complete your registration has been sent to {email}",
"terms-and-condition": "I confirm to the Terms and conditions."
@@ -786,9 +801,7 @@
}
},
"termsAndConditions": {
- "agree": "I agree!",
"newTermsAndConditions": "New Terms and Conditions",
- "termsAndConditionsConfirmed": "I have read and confirmed the terms and conditions.",
"termsAndConditionsNewConfirm": "I have read and agree to the new terms of conditions.",
"termsAndConditionsNewConfirmText": "Please read the new terms of use now!"
},
diff --git a/webapp/locales/es.json b/webapp/locales/es.json
index 659fd1995..ccc91ac4b 100644
--- a/webapp/locales/es.json
+++ b/webapp/locales/es.json
@@ -116,16 +116,6 @@
"versus": "Versus"
},
"components": {
- "enter-nonce": {
- "form": {
- "description": "Abra su buzón de correo e introduzca el código que le enviamos.",
- "next": "Continuar",
- "nonce": "Introduzca el código",
- "validations": {
- "length": "debe tener exactamente 6 letras"
- }
- }
- },
"password-reset": {
"change-password": {
"error": "Error al cambiar la contraseña. ¿Posiblemente un código de seguridad incorrecto?",
@@ -148,18 +138,23 @@
"success": "¡Su cuenta de usuario ha sido creada!",
"title": "Crear una cuenta de usuario"
},
+ "email-nonce": {
+ "form": {
+ "description": "Abra su buzón de correo e introduzca el código que le enviamos.",
+ "next": "Continuar",
+ "nonce": "Introduzca el código",
+ "validations": {
+ "length": "debe tener exactamente 5 letras"
+ }
+ }
+ },
"signup": {
"form": {
"data-privacy": "He leido y entendido la declaración de protección de datos.",
"description": "Para empezar, introduzca su dirección de correo electrónico:",
"errors": {
- "email-exists": "¡Ya hay una cuenta de usuario con esta dirección de correo electrónico!",
- "invalid-invitation-token": "Parece que el código de invitación ya ha sido canjeado. Cada código sólo se puede utilizar una vez."
+ "email-exists": "¡Ya hay una cuenta de usuario con esta dirección de correo electrónico!"
},
- "invitation-code": "Su código de invitación es: {code}",
- "minimum-age": "Tengo 18 años o más.",
- "no-commercial": "No tengo intensiones comerciales y no represento una empresa u organización comercial.",
- "no-political": "No estoy en la red en nombre de un partido o una organización política.",
"submit": "Crear una cuenta",
"success": "Se ha enviado un correo electrónico con un enlace de confirmación para el registro a {email}.",
"terms-and-condition": "Estoy de acuerdo con los términos de uso."
@@ -729,9 +724,7 @@
}
},
"termsAndConditions": {
- "agree": "¡Estoy de acuerdo!",
"newTermsAndConditions": "Nuevos términos de uso",
- "termsAndConditionsConfirmed": "He leído y acepto los términos de uso.",
"termsAndConditionsNewConfirm": "He leído y acepto los nuevos términos de uso.",
"termsAndConditionsNewConfirmText": "¡Por favor, lea los nuevos términos de uso ahora!"
},
diff --git a/webapp/locales/fr.json b/webapp/locales/fr.json
index d43007cf7..92d2ea79e 100644
--- a/webapp/locales/fr.json
+++ b/webapp/locales/fr.json
@@ -116,16 +116,6 @@
"versus": "Versus"
},
"components": {
- "enter-nonce": {
- "form": {
- "description": "Ouvrez votre boîte de réception et entrez le code que nous vous avons envoyé.",
- "next": "Continuer",
- "nonce": "Entrez votre code",
- "validations": {
- "length": "doit comporter 6 caractères"
- }
- }
- },
"password-reset": {
"change-password": {
"error": "La modification de votre mot de passe a échoué. Peut-être que le code de sécurité n'était pas correct ?",
@@ -148,18 +138,23 @@
"success": "Votre compte a été créé!",
"title": "Créer un compte utilisateur"
},
+ "email-nonce": {
+ "form": {
+ "description": "Ouvrez votre boîte de réception et entrez le code que nous vous avons envoyé.",
+ "next": "Continuer",
+ "nonce": "Entrez votre code",
+ "validations": {
+ "length": "doit comporter 5 caractères"
+ }
+ }
+ },
"signup": {
"form": {
"data-privacy": "J'ai lu et compris la Déclaration de confidentialité.",
"description": "Pour commencer, entrez votre adresse mail :",
"errors": {
- "email-exists": "Il existe déjà un compte utilisateur avec cette adresse mail!",
- "invalid-invitation-token": "On dirait que l'invitation a déjà été utilisée. Les liens d'invitation ne peuvent être utilisés qu'une seule fois."
+ "email-exists": "Il existe déjà un compte utilisateur avec cette adresse mail!"
},
- "invitation-code": "Votre code d'invitation est: {code} ",
- "minimum-age": "J'ai 18 ans ou plus.",
- "no-commercial": "Je n'ai aucun intérêt commercial et je ne représente pas d'entreprise ou toute autre organisation commerciale sur le réseau.",
- "no-political": "Je ne parle pas au nom d'un parti ou d'une organisation politique sur le réseau.",
"submit": "Créer un compte",
"success": "Un mail avec un lien pour compléter votre inscription a été envoyé à {email}",
"terms-and-condition": "Je confirme les Conditions générales."
@@ -697,9 +692,7 @@
}
},
"termsAndConditions": {
- "agree": "J'accepte!",
"newTermsAndConditions": "Nouvelles conditions générales",
- "termsAndConditionsConfirmed": "J'ai lu et accepte les conditions générales.",
"termsAndConditionsNewConfirm": "J'ai lu et accepté les nouvelles conditions générales.",
"termsAndConditionsNewConfirmText": "Veuillez lire les nouvelles conditions d'utilisation dès maintenant !"
},
diff --git a/webapp/locales/it.json b/webapp/locales/it.json
index 982f6f871..8e45554f7 100644
--- a/webapp/locales/it.json
+++ b/webapp/locales/it.json
@@ -123,16 +123,6 @@
"versus": "Verso"
},
"components": {
- "enter-nonce": {
- "form": {
- "description": null,
- "next": null,
- "nonce": null,
- "validations": {
- "length": null
- }
- }
- },
"password-reset": {
"change-password": {
"error": "Modifica della password non riuscita. Forse il codice di sicurezza non era corretto?",
@@ -155,16 +145,23 @@
"success": null,
"title": null
},
+ "email-nonce": {
+ "form": {
+ "description": null,
+ "next": null,
+ "nonce": null,
+ "validations": {
+ "length": null
+ }
+ }
+ },
"signup": {
"form": {
"data-privacy": null,
"description": null,
"errors": {
- "email-exists": null,
- "invalid-invitation-token": "Sembra che l'invito sia già stato utilizzato. I link di invito possono essere utilizzati una sola volta."
+ "email-exists": null
},
- "invitation-code": null,
- "minimum-age": null,
"submit": null,
"success": null,
"terms-and-condition": null
@@ -645,9 +642,7 @@
}
},
"termsAndConditions": {
- "agree": "Sono d'accordo!",
"newTermsAndConditions": "Nuovi Termini e Condizioni",
- "termsAndConditionsConfirmed": "Ho letto e confermato i Termini e condizioni.",
"termsAndConditionsNewConfirm": "Ho letto e accetto le nuove condizioni generali di contratto.",
"termsAndConditionsNewConfirmText": "Si prega di leggere le nuove condizioni d'uso ora!"
},
diff --git a/webapp/locales/pl.json b/webapp/locales/pl.json
index 8489609a6..9ac168fb7 100644
--- a/webapp/locales/pl.json
+++ b/webapp/locales/pl.json
@@ -83,16 +83,6 @@
"versus": "werset"
},
"components": {
- "enter-nonce": {
- "form": {
- "description": "Otwórz swoją skrzynkę odbiorczą i wpisz kod, który do Ciebie wysłaliśmy.",
- "next": "Kontynuuj",
- "nonce": "Wprowadź swój kod",
- "validations": {
- "length": "musi mieć długość 6 znaków."
- }
- }
- },
"password-reset": {
"change-password": {
"error": "Zmiana hasła nie powiodła się. Może kod bezpieczeństwa nie był poprawny?",
@@ -107,6 +97,18 @@
},
"title": "Zresetuj hasło"
}
+ },
+ "registration": {
+ "email-nonce": {
+ "form": {
+ "description": "Otwórz swoją skrzynkę odbiorczą i wpisz kod, który do Ciebie wysłaliśmy.",
+ "next": "Kontynuuj",
+ "nonce": "Wprowadź swój kod",
+ "validations": {
+ "length": "musi mieć długość 5 znaków."
+ }
+ }
+ }
}
},
"contribution": {
diff --git a/webapp/locales/pt.json b/webapp/locales/pt.json
index 6afddc3bb..f5897bc7b 100644
--- a/webapp/locales/pt.json
+++ b/webapp/locales/pt.json
@@ -163,16 +163,6 @@
"versus": "Contra"
},
"components": {
- "enter-nonce": {
- "form": {
- "description": "Abra a sua caixa de entrada e digite o código que lhe enviamos.",
- "next": "Continue",
- "nonce": "Digite seu código",
- "validations": {
- "length": "deve ter 6 caracteres"
- }
- }
- },
"password-reset": {
"change-password": {
"error": "A alteração da sua senha falhou. Talvez o código de segurança não estava correto?",
@@ -195,16 +185,23 @@
"success": "A sua conta foi criada!",
"title": "Criar uma conta de usuário"
},
+ "email-nonce": {
+ "form": {
+ "description": "Abra a sua caixa de entrada e digite o código que lhe enviamos.",
+ "next": "Continue",
+ "nonce": "Digite seu código",
+ "validations": {
+ "length": "deve ter 5 caracteres"
+ }
+ }
+ },
"signup": {
"form": {
"data-privacy": "Eu li e entendi o Política de Privacidade.",
"description": "Para começar, digite seu endereço de e-mail:",
"errors": {
- "email-exists": "Já existe uma conta de usuário com este endereço de e-mail!",
- "invalid-invitation-token": "Parece que o convite já foi usado. Os links para convites só podem ser usados uma vez."
+ "email-exists": "Já existe uma conta de usuário com este endereço de e-mail!"
},
- "invitation-code": "O seu código de convite é: {code}",
- "minimum-age": "Tenho 18 anos ou mais.",
"submit": "Criar uma conta",
"success": "Um e-mail com um link para completar o seu registo foi enviado para {email}",
"terms-and-condition": "Eu concordo com os Termos e condições."
@@ -680,9 +677,7 @@
}
},
"termsAndConditions": {
- "agree": "Eu concordo!",
"newTermsAndConditions": "Novos Termos e Condições",
- "termsAndConditionsConfirmed": "Eu li e confirmei os Terms and Conditions.",
"termsAndConditionsNewConfirm": "Eu li e concordo com os novos termos de condições.",
"termsAndConditionsNewConfirmText": "Por favor, leia os novos termos de uso agora!"
},
diff --git a/webapp/locales/ru.json b/webapp/locales/ru.json
index fe2e35969..2173e56a9 100644
--- a/webapp/locales/ru.json
+++ b/webapp/locales/ru.json
@@ -116,16 +116,6 @@
"versus": "Против"
},
"components": {
- "enter-nonce": {
- "form": {
- "description": "Откройте папку \\\"Входящие\\\" и введите код из сообщения.",
- "next": "Продолжить",
- "nonce": "Введите код",
- "validations": {
- "length": "длина должна быть 6 символов"
- }
- }
- },
"password-reset": {
"change-password": {
"error": "Смена пароля не удалась. Может быть, код безопасности был неправильным?",
@@ -148,18 +138,23 @@
"success": "Учетная запись успешно создана!",
"title": "Создать учетную запись"
},
+ "email-nonce": {
+ "form": {
+ "description": "Откройте папку \\\"Входящие\\\" и введите код из сообщения.",
+ "next": "Продолжить",
+ "nonce": "Введите код",
+ "validations": {
+ "length": "длина должна быть 5 символов"
+ }
+ }
+ },
"signup": {
"form": {
"data-privacy": "Я прочитал и понял Заявление о конфиденциальности",
"description": "Для начала работы введите свой адрес электронной почты:",
"errors": {
- "email-exists": "Уже есть учетная запись пользователя с этим адресом электронной почты!",
- "invalid-invitation-token": "Похоже, что приглашение уже было использовано. Ссылку из приглашения можно использовать только один раз."
+ "email-exists": "Уже есть учетная запись пользователя с этим адресом электронной почты!"
},
- "invitation-code": "Код приглашения: {code}",
- "minimum-age": "Мне 18 лет или более",
- "no-commercial": "У меня нет коммерческих намерений, и я не представляю коммерческое предприятие или организацию.",
- "no-political": "Я не от имени какой-либо партии или политической организации в сети.",
"submit": "Создать учетную запись",
"success": "Письмо со ссылкой для завершения регистрации было отправлено на {email} ",
"terms-and-condition": "Принимаю Условия и положения."
@@ -729,9 +724,7 @@
}
},
"termsAndConditions": {
- "agree": "Я согласен(на)!",
"newTermsAndConditions": "Новые условия и положения",
- "termsAndConditionsConfirmed": "Я прочитал(а) и подтверждаю Условия и положения.",
"termsAndConditionsNewConfirm": "Я прочитал(а) и согласен(на) с новыми условиями.",
"termsAndConditionsNewConfirmText": "Пожалуйста, ознакомьтесь с новыми условиями использования!"
},
diff --git a/webapp/middleware/authenticated.js b/webapp/middleware/authenticated.js
index e9417963b..3ea915bcc 100644
--- a/webapp/middleware/authenticated.js
+++ b/webapp/middleware/authenticated.js
@@ -22,5 +22,5 @@ export default async ({ store, env, route, redirect }) => {
params.path = route.path
}
- return redirect('/registration/signup', params)
+ return redirect('/registration', params)
}
diff --git a/webapp/nuxt.config.js b/webapp/nuxt.config.js
index 625710f97..1d38a3a0a 100644
--- a/webapp/nuxt.config.js
+++ b/webapp/nuxt.config.js
@@ -35,9 +35,7 @@ export default {
'password-reset-request',
'password-reset-enter-nonce',
'password-reset-change-password',
- 'registration-signup',
- 'registration-enter-nonce',
- 'registration-create-user-account',
+ 'registration',
'pages-slug',
'terms-and-conditions',
'code-of-conduct',
diff --git a/webapp/pages/registration.spec.js b/webapp/pages/registration.spec.js
new file mode 100644
index 000000000..b83cb6ad4
--- /dev/null
+++ b/webapp/pages/registration.spec.js
@@ -0,0 +1,467 @@
+import { config, mount } from '@vue/test-utils'
+import Registration from './registration.vue'
+import Vue from 'vue'
+
+const localVue = global.localVue
+
+config.stubs['client-only'] = ''
+config.stubs['router-link'] = ''
+config.stubs['nuxt-link'] = ''
+config.stubs['infinite-loading'] = ''
+
+describe('Registration', () => {
+ let wrapper
+ let Wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: (key) => key,
+ $i18n: {
+ locale: () => 'de',
+ },
+ $route: {
+ query: {},
+ },
+ $env: {},
+ }
+ })
+
+ describe('mount', () => {
+ Wrapper = () => {
+ return mount(Registration, {
+ mocks,
+ localVue,
+ })
+ }
+
+ describe('no "PUBLIC_REGISTRATION" and no "INVITE_REGISTRATION"', () => {
+ beforeEach(() => {
+ mocks.$env = {
+ PUBLIC_REGISTRATION: false,
+ INVITE_REGISTRATION: false,
+ }
+ })
+
+ it('no "method" query in URI show "RegistrationSlideNoPublic"', () => {
+ mocks.$route.query = {}
+ wrapper = Wrapper()
+ expect(wrapper.find('.hc-empty').exists()).toBe(true)
+ expect(wrapper.find('.enter-invite').exists()).toBe(false)
+ expect(wrapper.find('.enter-email').exists()).toBe(false)
+ })
+
+ describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
+ it('no "email" query in URI', () => {
+ mocks.$route.query = { method: 'invite-mail' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').exists()).toBe(true)
+ })
+
+ describe('"email=user%40example.org" query in URI', () => {
+ it('have email displayed', () => {
+ mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
+ })
+
+ it('"nonce=64835" query in URI have nonce in input', async () => {
+ mocks.$route.query = {
+ method: 'invite-mail',
+ email: 'user@example.org',
+ nonce: '64835',
+ }
+ wrapper = Wrapper()
+ await Vue.nextTick()
+ const form = wrapper.find('.enter-nonce')
+ expect(form.vm.formData.nonce).toEqual('64835')
+ })
+ })
+ })
+
+ describe('"method=invite-code" in URI show "RegistrationSlideNoPublic"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-code' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.hc-empty').exists()).toBe(true)
+ })
+
+ it('"inviteCode=AAAAAA" query in URI', () => {
+ mocks.$route.query = { method: 'invite-code', inviteCode: 'AAAAAA' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.hc-empty').exists()).toBe(true)
+ })
+ })
+ })
+
+ describe('no "PUBLIC_REGISTRATION" but "INVITE_REGISTRATION"', () => {
+ beforeEach(() => {
+ mocks.$env = {
+ PUBLIC_REGISTRATION: false,
+ INVITE_REGISTRATION: true,
+ }
+ })
+
+ it('no "method" query in URI show "RegistrationSlideInvite"', () => {
+ mocks.$route.query = {}
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-invite').exists()).toBe(true)
+ expect(wrapper.find('.enter-email').exists()).toBe(false)
+ })
+
+ describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-mail' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').exists()).toBe(true)
+ })
+
+ describe('"email=user%40example.org" query in URI', () => {
+ it('have email displayed', () => {
+ mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
+ })
+
+ it('"nonce=64835" query in URI have nonce in input', async () => {
+ mocks.$route.query = {
+ method: 'invite-mail',
+ email: 'user@example.org',
+ nonce: '64835',
+ }
+ wrapper = Wrapper()
+ await Vue.nextTick()
+ const form = wrapper.find('.enter-nonce')
+ expect(form.vm.formData.nonce).toEqual('64835')
+ })
+ })
+ })
+
+ describe('"method=invite-code" in URI show "RegistrationSlideInvite"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-code' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-invite').exists()).toBe(true)
+ })
+
+ it('"inviteCode=AAAAAA" query in URI have invite code in input', async () => {
+ mocks.$route.query = { method: 'invite-code', inviteCode: 'AAAAAA' }
+ wrapper = Wrapper()
+ await Vue.nextTick()
+ const form = wrapper.find('.enter-invite')
+ expect(form.vm.formData.inviteCode).toEqual('AAAAAA')
+ })
+ })
+ })
+
+ describe('"PUBLIC_REGISTRATION" but no "INVITE_REGISTRATION"', () => {
+ beforeEach(() => {
+ mocks.$env = {
+ PUBLIC_REGISTRATION: true,
+ INVITE_REGISTRATION: false,
+ }
+ })
+
+ it('no "method" query in URI show "RegistrationSlideEmail"', () => {
+ mocks.$route.query = {}
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-email').exists()).toBe(true)
+ expect(wrapper.find('.enter-invite').exists()).toBe(false)
+ })
+
+ describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-mail' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').exists()).toBe(true)
+ })
+
+ describe('"email=user%40example.org" query in URI', () => {
+ it('have email displayed', () => {
+ mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
+ })
+
+ it('"nonce=64835" query in URI have nonce in input', async () => {
+ mocks.$route.query = {
+ method: 'invite-mail',
+ email: 'user@example.org',
+ nonce: '64835',
+ }
+ wrapper = Wrapper()
+ await Vue.nextTick()
+ const form = wrapper.find('.enter-nonce')
+ expect(form.vm.formData.nonce).toEqual('64835')
+ })
+ })
+ })
+
+ describe('"method=invite-code" in URI show "RegistrationSlideEmail"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-code' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-email').exists()).toBe(true)
+ expect(wrapper.find('.enter-invite').exists()).toBe(false)
+ })
+ })
+ })
+
+ describe('"PUBLIC_REGISTRATION" and "INVITE_REGISTRATION"', () => {
+ beforeEach(() => {
+ mocks.$env = {
+ PUBLIC_REGISTRATION: true,
+ INVITE_REGISTRATION: true,
+ }
+ })
+
+ it('no "method" query in URI show "RegistrationSlideEmail"', () => {
+ mocks.$route.query = {}
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-email').exists()).toBe(true)
+ expect(wrapper.find('.enter-invite').exists()).toBe(false)
+ })
+
+ describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-mail' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').exists()).toBe(true)
+ })
+
+ describe('"email=user%40example.org" query in URI', () => {
+ it('have email displayed', () => {
+ mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
+ })
+
+ it('"nonce=64835" query in URI have nonce in input', async () => {
+ mocks.$route.query = {
+ method: 'invite-mail',
+ email: 'user@example.org',
+ nonce: '64835',
+ }
+ wrapper = Wrapper()
+ await Vue.nextTick()
+ const form = wrapper.find('.enter-nonce')
+ expect(form.vm.formData.nonce).toEqual('64835')
+ })
+ })
+ })
+
+ describe('"method=invite-code" in URI show "RegistrationSlideInvite"', () => {
+ it('no "inviteCode" query in URI', () => {
+ mocks.$route.query = { method: 'invite-code' }
+ wrapper = Wrapper()
+ expect(wrapper.find('.enter-invite').exists()).toBe(true)
+ })
+
+ it('"inviteCode=AAAAAA" query in URI have invite code in input', async () => {
+ mocks.$route.query = { method: 'invite-code', inviteCode: 'AAAAAA' }
+ wrapper = Wrapper()
+ await Vue.nextTick()
+ const form = wrapper.find('.enter-invite')
+ expect(form.vm.formData.inviteCode).toEqual('AAAAAA')
+ })
+ })
+ })
+
+ // copied from webapp/components/Registration/Signup.spec.js as testing template
+ // describe('with invitation code', () => {
+ // let action
+ // beforeEach(() => {
+ // propsData.token = '12345'
+ // action = async () => {
+ // wrapper = Wrapper()
+ // wrapper.find('input#email').setValue('mail@example.org')
+ // await wrapper.find('form').trigger('submit')
+ // await wrapper.html()
+ // }
+ // })
+
+ // describe('submit', () => {
+ // it('delivers invitation code to backend', async () => {
+ // await action()
+ // const expected = expect.objectContaining({
+ // mutation: SignupMutation,
+ // variables: { email: 'mail@example.org', inviteCode: '12345' },
+ // })
+ // expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
+ // })
+
+ // describe('in case a user account with the email already exists', () => {
+ // beforeEach(() => {
+ // mocks.$apollo.mutate = jest
+ // .fn()
+ // .mockRejectedValue(
+ // new Error('UserInputError: A user account with this email already exists.'),
+ // )
+ // })
+
+ // it('explains the error', async () => {
+ // await action()
+ // expect(mocks.$t).toHaveBeenCalledWith(
+ // 'components.registration.signup.form.errors.email-exists',
+ // )
+ // })
+ // })
+ // })
+ // })
+ })
+})
+
+// template from deleted webapp/components/Registration/CreateUserAccount.spec.js
+// import { config, mount } from '@vue/test-utils'
+// import Vue from 'vue'
+// import { VERSION } from '~/constants/terms-and-conditions-version.js'
+// import CreateUserAccount from './CreateUserAccount'
+// import { SignupVerificationMutation } from '~/graphql/Registration.js'
+// const localVue = global.localVue
+
+// config.stubs['sweetalert-icon'] = ''
+// config.stubs['client-only'] = ''
+// config.stubs['nuxt-link'] = ''
+
+// describe('CreateUserAccount', () => {
+// let wrapper, Wrapper, mocks, propsData, stubs
+
+// beforeEach(() => {
+// mocks = {
+// $toast: {
+// success: jest.fn(),
+// error: jest.fn(),
+// },
+// $t: jest.fn(),
+// $apollo: {
+// loading: false,
+// mutate: jest.fn(),
+// },
+// $i18n: {
+// locale: () => 'en',
+// },
+// }
+// propsData = {}
+// stubs = {
+// LocaleSwitch: "",
+// }
+// })
+
+// describe('mount', () => {
+// Wrapper = () => {
+// return mount(CreateUserAccount, {
+// mocks,
+// propsData,
+// localVue,
+// stubs,
+// })
+// }
+
+// describe('given email and nonce', () => {
+// beforeEach(() => {
+// propsData.nonce = '666777'
+// propsData.email = 'sixseven@example.org'
+// })
+
+// it('renders a form to create a new user', () => {
+// wrapper = Wrapper()
+// expect(wrapper.find('.create-user-account').exists()).toBe(true)
+// })
+
+// describe('submit', () => {
+// let action
+// beforeEach(() => {
+// action = async () => {
+// wrapper = Wrapper()
+// wrapper.find('input#name').setValue('John Doe')
+// wrapper.find('input#password').setValue('hellopassword')
+// wrapper.find('textarea#about').setValue('Hello I am the `about` attribute')
+// wrapper.find('input#passwordConfirmation').setValue('hellopassword')
+// wrapper.find('input#checkbox0').setChecked()
+// wrapper.find('input#checkbox1').setChecked()
+// wrapper.find('input#checkbox2').setChecked()
+// wrapper.find('input#checkbox3').setChecked()
+// wrapper.find('input#checkbox4').setChecked()
+// await wrapper.find('form').trigger('submit')
+// await wrapper.html()
+// }
+// })
+
+// it('delivers data to backend', async () => {
+// await action()
+// const expected = expect.objectContaining({
+// variables: {
+// about: 'Hello I am the `about` attribute',
+// name: 'John Doe',
+// email: 'sixseven@example.org',
+// nonce: '666777',
+// password: 'hellopassword',
+// termsAndConditionsAgreedVersion: VERSION,
+// locale: 'en',
+// },
+// })
+// expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
+// })
+
+// it('calls CreateUserAccount graphql mutation', async () => {
+// await action()
+// const expected = expect.objectContaining({ mutation: SignupVerificationMutation })
+// expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
+// })
+
+// describe('in case mutation resolves', () => {
+// beforeEach(() => {
+// mocks.$apollo.mutate = jest.fn().mockResolvedValue({
+// data: {
+// SignupVerification: {
+// id: 'u1',
+// name: 'John Doe',
+// slug: 'john-doe',
+// },
+// },
+// })
+// })
+
+// it('displays success', async () => {
+// await action()
+// await Vue.nextTick()
+// expect(mocks.$t).toHaveBeenCalledWith(
+// 'components.registration.create-user-account.success',
+// )
+// })
+
+// describe('after timeout', () => {
+// beforeEach(jest.useFakeTimers)
+
+// it('emits `userCreated` with { password, email }', async () => {
+// await action()
+// jest.runAllTimers()
+// expect(wrapper.emitted('userCreated')).toEqual([
+// [
+// {
+// email: 'sixseven@example.org',
+// password: 'hellopassword',
+// },
+// ],
+// ])
+// })
+// })
+// })
+
+// describe('in case mutation rejects', () => {
+// beforeEach(() => {
+// mocks.$apollo.mutate = jest.fn().mockRejectedValue(new Error('Invalid nonce'))
+// })
+
+// it('displays form errors', async () => {
+// await action()
+// await Vue.nextTick()
+// expect(mocks.$t).toHaveBeenCalledWith(
+// 'components.registration.create-user-account.error',
+// )
+// })
+// })
+// })
+// })
+// })
+// })
diff --git a/webapp/pages/registration.vue b/webapp/pages/registration.vue
index a3e735eb2..6d8818d07 100644
--- a/webapp/pages/registration.vue
+++ b/webapp/pages/registration.vue
@@ -1,33 +1,33 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
diff --git a/webapp/pages/registration/create-user-account.vue b/webapp/pages/registration/create-user-account.vue
deleted file mode 100644
index 677aea5eb..000000000
--- a/webapp/pages/registration/create-user-account.vue
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
diff --git a/webapp/pages/registration/enter-nonce.vue b/webapp/pages/registration/enter-nonce.vue
deleted file mode 100644
index 022435b6e..000000000
--- a/webapp/pages/registration/enter-nonce.vue
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- {{ $t('site.back-to-login') }}
-
-
-
-
-
diff --git a/webapp/pages/registration/signup.vue b/webapp/pages/registration/signup.vue
deleted file mode 100644
index 18f9c9a70..000000000
--- a/webapp/pages/registration/signup.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
- {{ $t('site.back-to-login') }}
-
-
-
-
- {{ $t('site.back-to-login') }}
-
-
-
-