mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge pull request #4168 from Ocelot-Social-Community/4092-redesign-registration-process
feat: 🍰 Redesign Registration Process Frontend
This commit is contained in:
commit
76d3788cf1
@ -16,6 +16,7 @@ describe('rewards', () => {
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
await cleanDatabase()
|
||||
const { server } = createServer({
|
||||
context: () => {
|
||||
return {
|
||||
|
||||
87
webapp/components/ComponentSlider/ComponentSlider.vue
Normal file
87
webapp/components/ComponentSlider/ComponentSlider.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="Sliders">
|
||||
<slot :name="'header'" />
|
||||
|
||||
<ds-heading v-if="sliderData.sliders[sliderIndex].title" size="h3">
|
||||
{{ sliderData.sliders[sliderIndex].title }}
|
||||
</ds-heading>
|
||||
|
||||
<slot :name="sliderData.sliders[sliderIndex].name" />
|
||||
|
||||
<ds-flex>
|
||||
<ds-flex-item :centered="true">
|
||||
<div
|
||||
v-for="(slider, index) in sliderData.sliders"
|
||||
:key="slider.name"
|
||||
:class="['Sliders__slider-selection', index < sliderIndex && '--confirmed']"
|
||||
>
|
||||
<base-button
|
||||
:class="['selection-dot']"
|
||||
style="float: left"
|
||||
:circle="true"
|
||||
size="small"
|
||||
type="submit"
|
||||
filled
|
||||
:loading="false"
|
||||
:disabled="index > sliderIndex"
|
||||
@click="sliderData.sliderSelectorCallback(index)"
|
||||
/>
|
||||
</div>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item>
|
||||
<base-button
|
||||
style="float: right"
|
||||
:icon="sliderData.sliders[sliderIndex].button.icon"
|
||||
type="submit"
|
||||
filled
|
||||
:loading="false"
|
||||
:disabled="!sliderData.sliders[sliderIndex].validated"
|
||||
@click="onNextClick"
|
||||
>
|
||||
{{ sliderData.sliders[sliderIndex].button.title }}
|
||||
</base-button>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
|
||||
<slot :name="'footer'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ComponentSlider',
|
||||
props: {
|
||||
sliderData: { type: Object, required: true },
|
||||
},
|
||||
computed: {
|
||||
sliderIndex() {
|
||||
return this.sliderData.sliderIndex // to have a shorter notation
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onNextClick() {
|
||||
let success = true
|
||||
if (this.sliderData.sliders[this.sliderIndex].button.sliderCallback) {
|
||||
success = await this.sliderData.sliders[this.sliderIndex].button.sliderCallback()
|
||||
}
|
||||
success = success && this.sliderData.sliders[this.sliderIndex].button.callback(success)
|
||||
if (success && this.sliderIndex < this.sliderData.sliders.length - 1) {
|
||||
this.sliderData.sliderSelectorCallback(this.sliderIndex + 1)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.Sliders {
|
||||
&__slider-selection {
|
||||
.selection-dot {
|
||||
margin-right: 2px;
|
||||
}
|
||||
&.--confirmed {
|
||||
opacity: $opacity-disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
webapp/components/Registration/CreateUserAccount.story.js
Normal file
84
webapp/components/Registration/CreateUserAccount.story.js
Normal file
@ -0,0 +1,84 @@
|
||||
import { storiesOf } from '@storybook/vue'
|
||||
import { withA11y } from '@storybook/addon-a11y'
|
||||
import { action } from '@storybook/addon-actions'
|
||||
import Vuex from 'vuex'
|
||||
import helpers from '~/storybook/helpers'
|
||||
import links from '~/constants/links.js'
|
||||
import metadata from '~/constants/metadata.js'
|
||||
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
||||
import CreateUserAccount from './CreateUserAccount.vue'
|
||||
|
||||
helpers.init()
|
||||
|
||||
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('CreateUserAccount', module)
|
||||
.addDecorator(withA11y)
|
||||
.addDecorator(helpers.layout)
|
||||
.add('standard', () => ({
|
||||
components: { LocaleSwitch, CreateUserAccount },
|
||||
store: createStore({ loginSuccess: true }),
|
||||
data: () => ({
|
||||
links,
|
||||
metadata,
|
||||
nonce: 'A34RB56',
|
||||
email: 'user@example.org',
|
||||
}),
|
||||
methods: {
|
||||
handleSuccess() {
|
||||
action('You are logged in!')()
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<ds-container width="small">
|
||||
<base-card>
|
||||
<template #imageColumn>
|
||||
<a :href="links.ORGANIZATION" :title="$t('login.moreInfo', metadata)" target="_blank">
|
||||
<img class="image" alt="Sign up" src="/img/custom/sign-up.svg" />
|
||||
</a>
|
||||
</template>
|
||||
<create-user-account @userCreated="handleSuccess" :email="email" :nonce="nonce" />
|
||||
<template #topMenu>
|
||||
<locale-switch offset="5" />
|
||||
</template>
|
||||
</base-card>
|
||||
</ds-container>
|
||||
`,
|
||||
}))
|
||||
@ -0,0 +1,321 @@
|
||||
<template>
|
||||
<div v-if="response === 'success'">
|
||||
<transition name="ds-transition-fade">
|
||||
<sweetalert-icon icon="success" />
|
||||
</transition>
|
||||
<ds-text align="center" bold color="success">
|
||||
{{ $t('components.registration.create-user-account.success') }}
|
||||
</ds-text>
|
||||
</div>
|
||||
<div v-else-if="response === 'error'">
|
||||
<transition name="ds-transition-fade">
|
||||
<sweetalert-icon icon="error" />
|
||||
</transition>
|
||||
<ds-text align="center" bold color="danger">
|
||||
{{ $t('components.registration.create-user-account.error') }}
|
||||
</ds-text>
|
||||
<ds-text align="center">
|
||||
{{ $t('components.registration.create-user-account.help') }}
|
||||
<a :href="'mailto:' + supportEmail">{{ supportEmail }}</a>
|
||||
</ds-text>
|
||||
<ds-space centered>
|
||||
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
|
||||
</ds-space>
|
||||
</div>
|
||||
<div v-else class="create-account-card">
|
||||
<!-- Wolle <ds-space margin-top="large">
|
||||
<ds-heading size="h3">
|
||||
{{ $t('components.registration.create-user-account.title') }}
|
||||
</ds-heading>
|
||||
</ds-space> -->
|
||||
|
||||
<ds-form
|
||||
class="create-user-account"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="submit"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
>
|
||||
<!-- leave this here in case the scoped variable is needed in the future nobody would remember this -->
|
||||
<!-- <template v-slot="{ errors }"> -->
|
||||
<template>
|
||||
<ds-input
|
||||
id="name"
|
||||
model="name"
|
||||
icon="user"
|
||||
:label="$t('settings.data.labelName')"
|
||||
:placeholder="$t('settings.data.namePlaceholder')"
|
||||
/>
|
||||
<ds-input
|
||||
id="about"
|
||||
model="about"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
:label="$t('settings.data.labelBio')"
|
||||
:placeholder="$t('settings.data.labelBio')"
|
||||
/>
|
||||
<ds-input
|
||||
id="password"
|
||||
model="password"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password')"
|
||||
/>
|
||||
<ds-input
|
||||
id="passwordConfirmation"
|
||||
model="passwordConfirmation"
|
||||
type="password"
|
||||
autocomplete="off"
|
||||
:label="$t('settings.security.change-password.label-new-password-confirm')"
|
||||
/>
|
||||
<password-strength class="password-strength" :password="formData.password" />
|
||||
|
||||
<ds-text>
|
||||
<!-- Wolle {{ $t('components.enter-nonce.form.description') }} -->
|
||||
Your e-mail address:
|
||||
<b>{{ this.sliderData.collectedInputData.email }}</b>
|
||||
</ds-text>
|
||||
|
||||
<ds-text>
|
||||
<input
|
||||
id="checkbox0"
|
||||
type="checkbox"
|
||||
v-model="termsAndConditionsConfirmed"
|
||||
:checked="termsAndConditionsConfirmed"
|
||||
/>
|
||||
<label for="checkbox0">
|
||||
{{ $t('termsAndConditions.termsAndConditionsConfirmed') }}
|
||||
<br />
|
||||
<nuxt-link to="/terms-and-conditions">{{ $t('site.termsAndConditions') }}</nuxt-link>
|
||||
</label>
|
||||
</ds-text>
|
||||
<ds-text>
|
||||
<input id="checkbox1" type="checkbox" v-model="dataPrivacy" :checked="dataPrivacy" />
|
||||
<label for="checkbox1">
|
||||
{{ $t('components.registration.signup.form.data-privacy') }}
|
||||
<br />
|
||||
<nuxt-link to="/data-privacy">
|
||||
{{ $t('site.data-privacy') }}
|
||||
</nuxt-link>
|
||||
</label>
|
||||
</ds-text>
|
||||
<ds-text>
|
||||
<input id="checkbox2" type="checkbox" v-model="minimumAge" :checked="minimumAge" />
|
||||
<label
|
||||
for="checkbox2"
|
||||
v-html="$t('components.registration.signup.form.minimum-age')"
|
||||
></label>
|
||||
</ds-text>
|
||||
<ds-text>
|
||||
<input id="checkbox3" type="checkbox" v-model="noCommercial" :checked="noCommercial" />
|
||||
<label
|
||||
for="checkbox3"
|
||||
v-html="$t('components.registration.signup.form.no-commercial')"
|
||||
></label>
|
||||
</ds-text>
|
||||
<ds-text>
|
||||
<input id="checkbox4" type="checkbox" v-model="noPolitical" :checked="noPolitical" />
|
||||
<label
|
||||
for="checkbox4"
|
||||
v-html="$t('components.registration.signup.form.no-political')"
|
||||
></label>
|
||||
</ds-text>
|
||||
</template>
|
||||
</ds-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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 { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
import PasswordForm from '~/components/utils/PasswordFormHelper'
|
||||
import { SignupVerificationMutation } from '~/graphql/Registration.js'
|
||||
|
||||
export default {
|
||||
name: 'RegistrationItemCreateUserAccount',
|
||||
components: {
|
||||
PasswordStrength,
|
||||
SweetalertIcon,
|
||||
},
|
||||
props: {
|
||||
sliderData: { type: Object, required: true },
|
||||
},
|
||||
data() {
|
||||
const passwordForm = PasswordForm({ translate: this.$t })
|
||||
return {
|
||||
links,
|
||||
supportEmail: emails.SUPPORT,
|
||||
formData: {
|
||||
name: '',
|
||||
about: '',
|
||||
...passwordForm.formData,
|
||||
},
|
||||
formSchema: {
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
min: 3,
|
||||
},
|
||||
about: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
...passwordForm.formSchema,
|
||||
},
|
||||
response: null, // Wolle
|
||||
// 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,
|
||||
}
|
||||
},
|
||||
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
|
||||
: ''
|
||||
this.formData.passwordConfirmation = this.sliderData.collectedInputData.passwordConfirmation
|
||||
? this.sliderData.collectedInputData.passwordConfirmation
|
||||
: ''
|
||||
this.termsAndConditionsConfirmed = this.sliderData.collectedInputData
|
||||
.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
|
||||
: false
|
||||
this.sendValidation()
|
||||
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
sliderSettings: { buttonSliderCallback: this.onNextClick },
|
||||
})
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
validInput() {
|
||||
return (
|
||||
this.formData.name.length >= 3 &&
|
||||
this.formData.password.length >= 1 &&
|
||||
this.formData.password === this.formData.passwordConfirmation &&
|
||||
this.termsAndConditionsConfirmed &&
|
||||
this.dataPrivacy &&
|
||||
this.minimumAge &&
|
||||
this.noCommercial &&
|
||||
this.noPolitical
|
||||
)
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
termsAndConditionsConfirmed() {
|
||||
this.sendValidation()
|
||||
},
|
||||
dataPrivacy() {
|
||||
this.sendValidation()
|
||||
},
|
||||
minimumAge() {
|
||||
this.sendValidation()
|
||||
},
|
||||
noCommercial() {
|
||||
this.sendValidation()
|
||||
},
|
||||
noPolitical() {
|
||||
this.sendValidation()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sendValidation() {
|
||||
const { name, about, password, passwordConfirmation } = this.formData
|
||||
const {
|
||||
termsAndConditionsConfirmed,
|
||||
dataPrivacy,
|
||||
minimumAge,
|
||||
noCommercial,
|
||||
noPolitical,
|
||||
} = this
|
||||
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
collectedInputData: {
|
||||
name,
|
||||
about,
|
||||
password,
|
||||
passwordConfirmation,
|
||||
termsAndConditionsConfirmed,
|
||||
dataPrivacy,
|
||||
minimumAge,
|
||||
noCommercial,
|
||||
noPolitical,
|
||||
},
|
||||
})
|
||||
},
|
||||
async handleInput() {
|
||||
this.sendValidation()
|
||||
},
|
||||
async handleInputValid() {
|
||||
this.sendValidation()
|
||||
},
|
||||
async submit() {
|
||||
const { name, password, about } = this.formData
|
||||
const { email, nonce } = this.sliderData.collectedInputData
|
||||
const termsAndConditionsAgreedVersion = VERSION
|
||||
const locale = this.$i18n.locale()
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: SignupVerificationMutation,
|
||||
variables: {
|
||||
name,
|
||||
password,
|
||||
about,
|
||||
email,
|
||||
nonce,
|
||||
termsAndConditionsAgreedVersion,
|
||||
locale,
|
||||
},
|
||||
})
|
||||
this.response = 'success'
|
||||
// Wolle setTimeout(() => {
|
||||
// this.$emit('userCreated', {
|
||||
// email,
|
||||
// password,
|
||||
// })
|
||||
// }, 3000)
|
||||
} catch (err) {
|
||||
this.response = 'error'
|
||||
}
|
||||
},
|
||||
onNextClick() {
|
||||
this.submit()
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.password-strength {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
</style>
|
||||
262
webapp/components/Registration/RegistrationItemEnterEmail.vue
Normal file
262
webapp/components/Registration/RegistrationItemEnterEmail.vue
Normal file
@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<!-- Wolle <ds-space v-if="!data && !error" margin="large"> -->
|
||||
<ds-form
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
>
|
||||
<!-- Wolle <h1>
|
||||
{{
|
||||
invitation
|
||||
? $t('profile.invites.title', metadata)
|
||||
: $t('components.registration.signup.title', metadata)
|
||||
}}
|
||||
</h1> -->
|
||||
<ds-text
|
||||
v-if="token"
|
||||
v-html="$t('registration.signup.form.invitation-code', { code: token })"
|
||||
/>
|
||||
<ds-text>
|
||||
{{
|
||||
invitation
|
||||
? $t('profile.invites.description')
|
||||
: $t('components.registration.signup.form.description')
|
||||
}}
|
||||
</ds-text>
|
||||
<ds-input
|
||||
:placeholder="invitation ? $t('profile.invites.emailPlaceholder') : $t('login.email')"
|
||||
type="email"
|
||||
id="email"
|
||||
model="email"
|
||||
name="email"
|
||||
icon="envelope"
|
||||
/>
|
||||
<slot></slot>
|
||||
<ds-text v-if="sliderData.collectedInputData.emailSend">
|
||||
<input id="checkbox" type="checkbox" v-model="sendEmailAgain" :checked="sendEmailAgain" />
|
||||
<label for="checkbox0">
|
||||
<!-- Wolle {{ $t('termsAndConditions.termsAndConditionsConfirmed') }} -->
|
||||
{{ 'Send e-mail again' }}
|
||||
</label>
|
||||
</ds-text>
|
||||
</ds-form>
|
||||
<!-- Wolle </ds-space>
|
||||
<div v-else margin="large">
|
||||
<template v-if="!error">
|
||||
<transition name="ds-transition-fade">
|
||||
<sweetalert-icon icon="info" />
|
||||
</transition>
|
||||
<ds-text align="center" v-html="submitMessage" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<transition name="ds-transition-fade">
|
||||
<sweetalert-icon icon="error" />
|
||||
</transition>
|
||||
<ds-text align="center">{{ error.message }}</ds-text>
|
||||
<ds-space centered class="space-top">
|
||||
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
|
||||
</ds-space>
|
||||
</template>
|
||||
</div> -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import metadata from '~/constants/metadata'
|
||||
import { isEmail } from 'validator'
|
||||
import normalizeEmail from '~/components/utils/NormalizeEmail'
|
||||
// Wolle import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
|
||||
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) {
|
||||
email
|
||||
}
|
||||
}
|
||||
`
|
||||
export default {
|
||||
name: 'RegistrationItemEnterEmail',
|
||||
components: {
|
||||
// Wolle SweetalertIcon,
|
||||
},
|
||||
props: {
|
||||
sliderData: { type: Object, required: true },
|
||||
token: { type: String, default: null }, // Wolle not used???
|
||||
invitation: { type: Boolean, default: false },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
metadata,
|
||||
formData: {
|
||||
email: '',
|
||||
},
|
||||
formSchema: {
|
||||
email: {
|
||||
type: 'email',
|
||||
required: true,
|
||||
message: this.$t('common.validations.email'),
|
||||
},
|
||||
},
|
||||
// TODO: Our styleguide does not support checkmarks.
|
||||
// Integrate termsAndConditionsConfirmed into `this.formData` once we
|
||||
// have checkmarks available.
|
||||
sendEmailAgain: false,
|
||||
error: null, // Wolle
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.$nextTick(function () {
|
||||
// Code that will run only after the entire view has been rendered
|
||||
this.formData.email = this.sliderData.collectedInputData.email
|
||||
? this.sliderData.collectedInputData.email
|
||||
: ''
|
||||
this.sendValidation()
|
||||
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
sliderSettings: {
|
||||
...this.buttonValues().sliderSettings,
|
||||
buttonSliderCallback: this.onNextClick,
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
sendEmailAgain() {
|
||||
this.setButtonValues()
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sliderIndex() {
|
||||
return this.sliderData.sliderIndex // to have a shorter notation
|
||||
},
|
||||
// Wolle submitMessage() {
|
||||
// const { email } = this.data.Signup
|
||||
// return this.$t('components.registration.signup.form.success', { email })
|
||||
// },
|
||||
validInput() {
|
||||
return isEmail(this.formData.email)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async sendValidation() {
|
||||
if (this.formData.email && isEmail(this.formData.email)) {
|
||||
this.formData.email = normalizeEmail(this.formData.email)
|
||||
}
|
||||
const { email } = this.formData
|
||||
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, { collectedInputData: { email } })
|
||||
},
|
||||
async handleInput() {
|
||||
this.sendValidation()
|
||||
},
|
||||
async handleInputValid() {
|
||||
this.sendValidation()
|
||||
},
|
||||
buttonValues() {
|
||||
return {
|
||||
sliderSettings: {
|
||||
buttonTitle: this.sliderData.collectedInputData.emailSend
|
||||
? this.sendEmailAgain
|
||||
? 'Resend e-mail'
|
||||
: 'Skip resend'
|
||||
: 'Send e-mail', // Wolle
|
||||
buttonIcon: this.sliderData.collectedInputData.emailSend
|
||||
? this.sendEmailAgain
|
||||
? 'envelope'
|
||||
: 'arrow-right'
|
||||
: 'envelope', // Wolle
|
||||
},
|
||||
}
|
||||
},
|
||||
setButtonValues() {
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, this.buttonValues())
|
||||
},
|
||||
async onNextClick() {
|
||||
const mutation = this.token ? SignupByInvitationMutation : SignupMutation
|
||||
const { token } = this
|
||||
const { email } = this.formData
|
||||
const variables = { email, token }
|
||||
|
||||
if (!this.sendEmailAgain && this.sliderData.collectedInputData.emailSend) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
this.sendEmailAgain ||
|
||||
!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 } },
|
||||
)
|
||||
|
||||
try {
|
||||
const response = await this.$apollo.mutate({ mutation, variables }) // e-mail is send in emailMiddleware of backend
|
||||
this.sliderData.setSliderValuesCallback(
|
||||
this.sliderData.sliders[this.sliderIndex].validated,
|
||||
{ sliderData: { response: response.data } },
|
||||
)
|
||||
|
||||
if (this.sliderData.sliders[this.sliderIndex].data.response) {
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
collectedInputData: { emailSend: true },
|
||||
})
|
||||
this.setButtonValues()
|
||||
|
||||
const { email: respnseEmail } =
|
||||
this.sliderData.sliders[this.sliderIndex].data.response.Signup ||
|
||||
this.sliderData.sliders[this.sliderIndex].data.response.SignupByInvitation
|
||||
this.$toast.success(
|
||||
this.$t('components.registration.email.form.success', { email: respnseEmail }),
|
||||
)
|
||||
}
|
||||
return true
|
||||
} catch (err) {
|
||||
this.sliderData.setSliderValuesCallback(
|
||||
this.sliderData.sliders[this.sliderIndex].validated,
|
||||
{ sliderData: { request: null, response: null } },
|
||||
)
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
collectedInputData: { emailSend: false },
|
||||
})
|
||||
this.setButtonValues()
|
||||
|
||||
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)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.space-top {
|
||||
margin-top: 6ex;
|
||||
}
|
||||
</style>
|
||||
145
webapp/components/Registration/RegistrationItemEnterInvite.vue
Normal file
145
webapp/components/Registration/RegistrationItemEnterInvite.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<ds-form
|
||||
class="enter-invite"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
>
|
||||
<ds-input
|
||||
:placeholder="$t('components.enter-invite.form.invite-code')"
|
||||
model="inviteCode"
|
||||
name="inviteCode"
|
||||
id="inviteCode"
|
||||
icon="question-circle"
|
||||
/>
|
||||
<ds-text>
|
||||
{{ $t('components.enter-invite.form.description') }}
|
||||
</ds-text>
|
||||
<slot></slot>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const isValidInviteCodeQuery = gql`
|
||||
query($code: ID!) {
|
||||
isValidInviteCode(code: $code)
|
||||
}
|
||||
`
|
||||
export default {
|
||||
name: 'RegistrationItemEnterInvite',
|
||||
props: {
|
||||
sliderData: { type: Object, required: true },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
inviteCode: '',
|
||||
},
|
||||
formSchema: {
|
||||
inviteCode: {
|
||||
type: 'string',
|
||||
// Wolle min: 6,
|
||||
// max: 6,
|
||||
required: true,
|
||||
message: this.$t('components.enter-invite.form.validations.length'),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
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
|
||||
: ''
|
||||
this.sendValidation()
|
||||
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
sliderSettings: { buttonSliderCallback: this.onNextClick },
|
||||
})
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
sliderIndex() {
|
||||
return this.sliderData.sliderIndex // to have a shorter notation
|
||||
},
|
||||
validInput() {
|
||||
return this.formData.inviteCode.length === 6
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async sendValidation() {
|
||||
const { inviteCode } = this.formData
|
||||
|
||||
let dbValidated = false
|
||||
if (this.validInput) {
|
||||
await this.handleSubmitVerify()
|
||||
dbValidated = this.sliderData.sliders[this.sliderIndex].data.response.isValidInviteCode
|
||||
}
|
||||
this.sliderData.setSliderValuesCallback(dbValidated, { collectedInputData: { inviteCode } })
|
||||
},
|
||||
async handleInput() {
|
||||
this.sendValidation()
|
||||
},
|
||||
async handleInputValid() {
|
||||
this.sendValidation()
|
||||
},
|
||||
async handleSubmitVerify() {
|
||||
const { inviteCode } = this.formData
|
||||
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 } },
|
||||
)
|
||||
|
||||
try {
|
||||
const response = await this.$apollo.query({ query: isValidInviteCodeQuery, variables })
|
||||
this.sliderData.setSliderValuesCallback(
|
||||
this.sliderData.sliders[this.sliderIndex].validated,
|
||||
{ sliderData: { response: response.data } },
|
||||
)
|
||||
|
||||
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 }),
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
this.sliderData.setSliderValuesCallback(
|
||||
this.sliderData.sliders[this.sliderIndex].validated,
|
||||
{ sliderData: { response: { isValidInviteCode: false } } },
|
||||
)
|
||||
|
||||
const { message } = err
|
||||
this.$toast.error(message)
|
||||
}
|
||||
}
|
||||
},
|
||||
onNextClick() {
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.enter-invite {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: $space-large 0 $space-xxx-small 0;
|
||||
}
|
||||
</style>
|
||||
107
webapp/components/Registration/RegistrationItemEnterNonce.vue
Normal file
107
webapp/components/Registration/RegistrationItemEnterNonce.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<ds-form
|
||||
class="enter-nonce"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="handleSubmitVerify"
|
||||
@input="handleInput"
|
||||
@input-valid="handleInputValid"
|
||||
>
|
||||
<ds-text>
|
||||
<!-- Wolle {{ $t('components.enter-nonce.form.description') }} -->
|
||||
Your e-mail address:
|
||||
<b>{{ this.sliderData.collectedInputData.email }}</b>
|
||||
</ds-text>
|
||||
<ds-input
|
||||
:placeholder="$t('components.enter-nonce.form.nonce')"
|
||||
model="nonce"
|
||||
name="nonce"
|
||||
id="nonce"
|
||||
icon="question-circle"
|
||||
/>
|
||||
<ds-text>
|
||||
{{ $t('components.enter-nonce.form.description') }}
|
||||
</ds-text>
|
||||
<slot></slot>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'RegistrationItemEnterNonce',
|
||||
props: {
|
||||
sliderData: { type: Object, required: true },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
nonce: '',
|
||||
},
|
||||
formSchema: {
|
||||
nonce: {
|
||||
type: 'string',
|
||||
// Wolle min: 6,
|
||||
// max: 6,
|
||||
required: true,
|
||||
message: this.$t('components.enter-nonce.form.validations.length'),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.$nextTick(function () {
|
||||
// Code that will run only after the entire view has been rendered
|
||||
// console.log('mounted !!! ')
|
||||
this.formData.nonce = this.sliderData.collectedInputData.nonce
|
||||
? this.sliderData.collectedInputData.nonce
|
||||
: ''
|
||||
this.sendValidation()
|
||||
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
sliderSettings: { buttonSliderCallback: this.onNextClick },
|
||||
})
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
validInput() {
|
||||
return this.formData.nonce.length === 6
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sendValidation() {
|
||||
const { nonce } = this.formData
|
||||
|
||||
// Wolle shall the nonce be validated in the database?
|
||||
// let dbValidated = false
|
||||
// if (this.validInput) {
|
||||
// await this.handleSubmitVerify()
|
||||
// dbValidated = this.sliderData.sliders[this.sliderIndex].data.response.isValidInviteCode
|
||||
// }
|
||||
// this.sliderData.setSliderValuesCallback(dbValidated, {
|
||||
this.sliderData.setSliderValuesCallback(this.validInput, {
|
||||
collectedInputData: {
|
||||
nonce,
|
||||
},
|
||||
})
|
||||
},
|
||||
async handleInput() {
|
||||
this.sendValidation()
|
||||
},
|
||||
async handleInputValid() {
|
||||
this.sendValidation()
|
||||
},
|
||||
handleSubmitVerify() {},
|
||||
onNextClick() {
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.enter-nonce {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: $space-large 0 $space-xxx-small 0;
|
||||
}
|
||||
</style>
|
||||
160
webapp/components/Registration/RegistrationSlider.story.js
Normal file
160
webapp/components/Registration/RegistrationSlider.story.js
Normal file
@ -0,0 +1,160 @@
|
||||
import { storiesOf } from '@storybook/vue'
|
||||
import { withA11y } from '@storybook/addon-a11y'
|
||||
import RegistrationSlider from './RegistrationSlider.vue'
|
||||
import helpers from '~/storybook/helpers'
|
||||
import Vue from 'vue'
|
||||
|
||||
const plugins = [
|
||||
(app = {}) => {
|
||||
app.$apollo = {
|
||||
mutate: (data) => {
|
||||
if (JSON.stringify(data).includes('UpdateUser')) {
|
||||
return { data: { UpdateUser: { id: data.variables.id, locale: data.variables.locale } } }
|
||||
}
|
||||
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 } } }
|
||||
}
|
||||
throw new Error(`Mutation name not found!`)
|
||||
},
|
||||
query: (data) => {
|
||||
if (JSON.stringify(data).includes('isValidInviteCode')) {
|
||||
return { data: { isValidInviteCode: true } }
|
||||
}
|
||||
throw new Error(`Query name not found!`)
|
||||
},
|
||||
}
|
||||
Vue.prototype.$apollo = app.$apollo
|
||||
return app
|
||||
},
|
||||
]
|
||||
helpers.init({ plugins })
|
||||
|
||||
storiesOf('RegistrationSlider', module)
|
||||
.addDecorator(withA11y)
|
||||
.addDecorator(helpers.layout)
|
||||
.add('invite-code empty', () => ({
|
||||
components: { RegistrationSlider },
|
||||
store: helpers.store,
|
||||
data: () => ({}),
|
||||
template: `
|
||||
<registration-slider registrationType="invite-code" />
|
||||
`,
|
||||
}))
|
||||
.add('invite-code with data', () => ({
|
||||
components: { RegistrationSlider },
|
||||
store: helpers.store,
|
||||
data: () => ({
|
||||
overwriteSliderData: {
|
||||
collectedInputData: {
|
||||
inviteCode: 'IN1T6Y',
|
||||
email: 'wolle.huss@pjannto.com',
|
||||
emailSend: false,
|
||||
nonce: 'NTRSCZ',
|
||||
name: 'Wolle',
|
||||
password: 'Hello',
|
||||
passwordConfirmation: 'Hello',
|
||||
about: `Hey`,
|
||||
termsAndConditionsConfirmed: true,
|
||||
dataPrivacy: true,
|
||||
minimumAge: true,
|
||||
noCommercial: true,
|
||||
noPolitical: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
template: `
|
||||
<registration-slider registrationType="invite-code" :overwriteSliderData="overwriteSliderData" />
|
||||
`,
|
||||
}))
|
||||
.add('public-registration empty', () => ({
|
||||
components: { RegistrationSlider },
|
||||
store: helpers.store,
|
||||
data: () => ({}),
|
||||
template: `
|
||||
<registration-slider registrationType="public-registration" />
|
||||
`,
|
||||
}))
|
||||
.add('public-registration with data', () => ({
|
||||
components: { RegistrationSlider },
|
||||
store: helpers.store,
|
||||
data: () => ({
|
||||
overwriteSliderData: {
|
||||
collectedInputData: {
|
||||
inviteCode: null,
|
||||
email: 'wolle.huss@pjannto.com',
|
||||
emailSend: false,
|
||||
nonce: 'NTRSCZ',
|
||||
name: 'Wolle',
|
||||
password: 'Hello',
|
||||
passwordConfirmation: 'Hello',
|
||||
about: `Hey`,
|
||||
termsAndConditionsConfirmed: true,
|
||||
dataPrivacy: true,
|
||||
minimumAge: true,
|
||||
noCommercial: true,
|
||||
noPolitical: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
template: `
|
||||
<registration-slider registrationType="public-registration" :overwriteSliderData="overwriteSliderData" />
|
||||
`,
|
||||
}))
|
||||
.add('invite-mail empty', () => ({
|
||||
components: { RegistrationSlider },
|
||||
store: helpers.store,
|
||||
data: () => ({
|
||||
overwriteSliderData: {
|
||||
collectedInputData: {
|
||||
inviteCode: null,
|
||||
email: 'wolle.huss@pjannto.com',
|
||||
emailSend: true,
|
||||
nonce: null,
|
||||
name: null,
|
||||
password: null,
|
||||
passwordConfirmation: null,
|
||||
about: null,
|
||||
termsAndConditionsConfirmed: null,
|
||||
dataPrivacy: null,
|
||||
minimumAge: null,
|
||||
noCommercial: null,
|
||||
noPolitical: null,
|
||||
},
|
||||
},
|
||||
}),
|
||||
template: `
|
||||
<registration-slider registrationType="invite-mail" :overwriteSliderData="overwriteSliderData" />
|
||||
`,
|
||||
}))
|
||||
.add('invite-mail with data', () => ({
|
||||
components: { RegistrationSlider },
|
||||
store: helpers.store,
|
||||
data: () => ({
|
||||
overwriteSliderData: {
|
||||
collectedInputData: {
|
||||
inviteCode: null,
|
||||
email: 'wolle.huss@pjannto.com',
|
||||
emailSend: true,
|
||||
nonce: 'NTRSCZ',
|
||||
name: 'Wolle',
|
||||
password: 'Hello',
|
||||
passwordConfirmation: 'Hello',
|
||||
about: `Hey`,
|
||||
termsAndConditionsConfirmed: true,
|
||||
dataPrivacy: true,
|
||||
minimumAge: true,
|
||||
noCommercial: true,
|
||||
noPolitical: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
template: `
|
||||
<registration-slider registrationType="invite-mail" :overwriteSliderData="overwriteSliderData" />
|
||||
`,
|
||||
}))
|
||||
235
webapp/components/Registration/RegistrationSlider.vue
Normal file
235
webapp/components/Registration/RegistrationSlider.vue
Normal file
@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<section class="login-form">
|
||||
<base-card>
|
||||
<template #imageColumn>
|
||||
<a :href="links.ORGANIZATION" :title="$t('login.moreInfo', metadata)" target="_blank">
|
||||
<img class="image" alt="Welcome" src="/img/custom/welcome.svg" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<component-slider :sliderData="sliderData">
|
||||
<template #header>
|
||||
<ds-heading size="h2">
|
||||
{{ $t('components.registration.signup.title', metadata) }}
|
||||
</ds-heading>
|
||||
</template>
|
||||
|
||||
<template v-if="['invite-code'].includes(registrationType)" #enter-invite>
|
||||
<registration-item-enter-invite :sliderData="sliderData" />
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-if="['invite-code', 'public-registration'].includes(registrationType)"
|
||||
#enter-email
|
||||
>
|
||||
<!-- Wolle !!! may create same source with 'webapp/pages/registration/signup.vue' -->
|
||||
<!-- <signup v-if="publicRegistration" :invitation="false" @submit="handleSubmitted"> -->
|
||||
<registration-item-enter-email :sliderData="sliderData" :invitation="false" />
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-if="['invite-code', 'public-registration', 'invite-mail'].includes(registrationType)"
|
||||
#enter-nonce
|
||||
>
|
||||
<registration-item-enter-nonce :sliderData="sliderData" />
|
||||
</template>
|
||||
|
||||
<template #create-user-account>
|
||||
<registration-item-create-user-account :sliderData="sliderData" />
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<ds-space margin-bottom="xxx-small" margin-top="small" centered>
|
||||
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
|
||||
</ds-space>
|
||||
</template>
|
||||
</component-slider>
|
||||
|
||||
<template #topMenu>
|
||||
<locale-switch offset="5" />
|
||||
</template>
|
||||
</base-card>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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'
|
||||
|
||||
export default {
|
||||
name: 'RegistrationSlider',
|
||||
components: {
|
||||
ComponentSlider,
|
||||
LocaleSwitch,
|
||||
RegistrationItemCreateUserAccount,
|
||||
RegistrationItemEnterEmail,
|
||||
RegistrationItemEnterInvite,
|
||||
RegistrationItemEnterNonce,
|
||||
},
|
||||
props: {
|
||||
registrationType: { type: String, required: true },
|
||||
overwriteSliderData: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
const slidersPortfolio = [
|
||||
{
|
||||
name: 'enter-invite',
|
||||
// title: this.$t('components.registration.create-user-account.title'),
|
||||
title: 'Invitation', // Wolle
|
||||
validated: false,
|
||||
data: { request: null, response: { isValidInviteCode: false } },
|
||||
button: {
|
||||
title: 'Next', // Wolle
|
||||
icon: 'arrow-right',
|
||||
callback: this.buttonCallback,
|
||||
sliderCallback: null, // optional set by slot
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'enter-email',
|
||||
title: 'E-Mail', // Wolle
|
||||
validated: false,
|
||||
data: { request: null, response: null },
|
||||
button: {
|
||||
title: '', // set by slider component
|
||||
icon: '', // set by slider component
|
||||
callback: this.buttonCallback,
|
||||
sliderCallback: null, // optional set by slot
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'enter-nonce',
|
||||
title: 'E-Mail Confirmation', // Wolle
|
||||
validated: false,
|
||||
data: { request: null, response: null },
|
||||
button: {
|
||||
title: 'Confirm', // Wolle
|
||||
icon: 'arrow-right',
|
||||
callback: this.buttonCallback,
|
||||
sliderCallback: null, // optional set by slot
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'create-user-account',
|
||||
title: this.$t('components.registration.create-user-account.title'),
|
||||
validated: false,
|
||||
data: { request: null, response: null },
|
||||
button: {
|
||||
// title: this.$t('actions.save'), // Wolle
|
||||
title: 'Create', // Wolle
|
||||
icon: 'check',
|
||||
callback: this.buttonCallback,
|
||||
sliderCallback: null, // optional set by slot
|
||||
},
|
||||
},
|
||||
]
|
||||
let sliders = []
|
||||
switch (this.registrationType) {
|
||||
case 'invite-code':
|
||||
sliders = [
|
||||
slidersPortfolio[0],
|
||||
slidersPortfolio[1],
|
||||
slidersPortfolio[2],
|
||||
slidersPortfolio[3],
|
||||
]
|
||||
break
|
||||
case 'public-registration':
|
||||
sliders = [slidersPortfolio[1], slidersPortfolio[2], slidersPortfolio[3]]
|
||||
break
|
||||
case 'invite-mail':
|
||||
sliders = [slidersPortfolio[2], slidersPortfolio[3]]
|
||||
break
|
||||
}
|
||||
|
||||
return {
|
||||
links,
|
||||
metadata,
|
||||
sliderData: {
|
||||
collectedInputData: {
|
||||
inviteCode: null,
|
||||
email: null,
|
||||
emailSend: null,
|
||||
nonce: null,
|
||||
name: null,
|
||||
password: null,
|
||||
passwordConfirmation: null,
|
||||
about: null,
|
||||
termsAndConditionsConfirmed: null,
|
||||
dataPrivacy: null,
|
||||
minimumAge: null,
|
||||
noCommercial: null,
|
||||
noPolitical: null,
|
||||
},
|
||||
sliderIndex: 0,
|
||||
sliders: sliders,
|
||||
sliderSelectorCallback: this.sliderSelectorCallback,
|
||||
setSliderValuesCallback: this.setSliderValuesCallback,
|
||||
...this.overwriteSliderData,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sliderIndex() {
|
||||
return this.sliderData.sliderIndex // to have a shorter notation
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setSliderValuesCallback(isValid, { 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 (collectedInputData) {
|
||||
this.sliderData.collectedInputData = {
|
||||
...this.sliderData.collectedInputData,
|
||||
...collectedInputData,
|
||||
}
|
||||
}
|
||||
if (sliderData) {
|
||||
if (this.sliderData.sliders[this.sliderIndex].data) {
|
||||
this.sliderData.sliders[this.sliderIndex].data = {
|
||||
request: sliderData.request
|
||||
? sliderData.request
|
||||
: this.sliderData.sliders[this.sliderIndex].data.request,
|
||||
response: sliderData.response
|
||||
? sliderData.response
|
||||
: this.sliderData.sliders[this.sliderIndex].data.response,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sliderSettings) {
|
||||
const { buttonTitle, buttonIcon, buttonSliderCallback } = sliderSettings
|
||||
if (buttonTitle) {
|
||||
this.sliderData.sliders[this.sliderIndex].button.title = buttonTitle
|
||||
}
|
||||
if (buttonIcon) {
|
||||
this.sliderData.sliders[this.sliderIndex].button.icon = buttonIcon
|
||||
}
|
||||
if (buttonSliderCallback) {
|
||||
this.sliderData.sliders[this.sliderIndex].button.sliderCallback = buttonSliderCallback
|
||||
}
|
||||
}
|
||||
},
|
||||
sliderSelectorCallback(selectedIndex) {
|
||||
// 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
|
||||
|
||||
if (selectedIndex <= this.sliderIndex + 1 && selectedIndex < this.sliderData.sliders.length) {
|
||||
this.sliderData.sliderIndex = selectedIndex
|
||||
}
|
||||
},
|
||||
buttonCallback(success) {
|
||||
// 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
|
||||
|
||||
return success
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
@ -15,7 +15,7 @@ export default function PasswordForm({ translate }) {
|
||||
},
|
||||
passwordConfirmation: [
|
||||
{
|
||||
validator(rule, value, callback, source, options) {
|
||||
validator(_rule, value, callback, source, _options) {
|
||||
var errors = []
|
||||
if (source.password !== value) {
|
||||
errors.push(new Error(passwordMismatchMessage))
|
||||
|
||||
@ -120,6 +120,16 @@
|
||||
"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.",
|
||||
@ -152,9 +162,19 @@
|
||||
"success": "Dein Benutzerkonto wurde erstellt!",
|
||||
"title": "Benutzerkonto anlegen"
|
||||
},
|
||||
"email": {
|
||||
"form": {
|
||||
"success": "Verifikations-E-Mail gesendet an <b>{email}</b>!"
|
||||
}
|
||||
},
|
||||
"invite-code": {
|
||||
"form": {
|
||||
"success": "Gültiger Einladungs-Code <b>{inviteCode}</b>!"
|
||||
}
|
||||
},
|
||||
"signup": {
|
||||
"form": {
|
||||
"data-privacy": "Ich habe die <a href=\"/data-privacy\" target=\"_blank\"><ds-text bold color=\"primary\">Datenschutzerklärung</ds-text></a> gelesen und verstanden",
|
||||
"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!",
|
||||
@ -733,7 +753,7 @@
|
||||
"bank": "Bankverbindung",
|
||||
"code-of-conduct": "Verhaltenscodex",
|
||||
"contact": "Kontakt",
|
||||
"data-privacy": "Datenschutz",
|
||||
"data-privacy": "Datenschutzerklärung",
|
||||
"director": "Geschäftsführer",
|
||||
"error-occurred": "Ein Fehler ist aufgetreten.",
|
||||
"faq": "FAQ",
|
||||
|
||||
@ -120,6 +120,16 @@
|
||||
"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.",
|
||||
@ -152,9 +162,19 @@
|
||||
"success": "Your account has been created!",
|
||||
"title": "Create user account"
|
||||
},
|
||||
"email": {
|
||||
"form": {
|
||||
"success": "Verification e-mail send to <b>{email}</b>!"
|
||||
}
|
||||
},
|
||||
"invite-code": {
|
||||
"form": {
|
||||
"success": "Valid invite code <b>{inviteCode}</b>!"
|
||||
}
|
||||
},
|
||||
"signup": {
|
||||
"form": {
|
||||
"data-privacy": "I have read and understood the <a href=\"/data-privacy\" target=\"_blank\"><ds-text bold color=\"primary\">Privacy Statement</ds-text></a>.",
|
||||
"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!",
|
||||
@ -762,7 +782,7 @@
|
||||
"termsAndConditions": {
|
||||
"agree": "I agree!",
|
||||
"newTermsAndConditions": "New Terms and Conditions",
|
||||
"termsAndConditionsConfirmed": "I have read and confirmed the 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!"
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user