refactor: DRY template in pages, fix signup flow

This commit is contained in:
roschaefer 2019-10-07 22:36:44 +02:00 committed by mattwr18
parent 1dc4bc1411
commit 4c7cc0a9cf
6 changed files with 151 additions and 137 deletions

View File

@ -1,98 +1,78 @@
<template> <template>
<ds-container width="small"> <ds-space v-if="success">
<ds-card v-if="success" class="success"> <sweetalert-icon icon="success" />
<ds-space> <ds-text align="center" bold color="success">
<sweetalert-icon icon="success" /> {{ $t('registration.create-user-account.success') }}
<ds-text align="center" bold color="success"> </ds-text>
{{ $t('registration.create-user-account.success') }} </ds-space>
</ds-text> <div v-else class="create-account-card">
</ds-space> <ds-space margin-top="large">
</ds-card> <ds-heading size="h3">
<ds-card v-else class="create-account-card"> {{ $t('components.registration.create-user-account.title') }}
<client-only> </ds-heading>
<locale-switch /> </ds-space>
</client-only>
<ds-space centered> <ds-form class="create-user-account" v-model="formData" :schema="formSchema" @submit="submit">
<img <template v-slot="{ errors }">
class="create-account-image" <ds-input
alt="Create an account for Human Connection" id="name"
src="/img/sign-up/nicetomeetyou.svg" model="name"
icon="user"
:label="$t('settings.data.labelName')"
:placeholder="$t('settings.data.namePlaceholder')"
/> />
</ds-space> <ds-input
<ds-space> id="about"
<ds-heading size="h3"> model="about"
{{ $t('registration.create-user-account.title') }} type="textarea"
</ds-heading> rows="3"
</ds-space> :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 :password="formData.password" />
<ds-form class="create-user-account" v-model="formData" :schema="formSchema" @submit="submit"> <ds-text>
<template v-slot="{ errors }"> <input
<ds-flex gutter="base"> id="checkbox"
<ds-flex-item width="100%"> type="checkbox"
<ds-input v-model="termsAndConditionsConfirmed"
id="name" :checked="termsAndConditionsConfirmed"
model="name" />
icon="user" <label
:label="$t('settings.data.labelName')" for="checkbox"
:placeholder="$t('settings.data.namePlaceholder')" v-html="$t('termsAndConditions.termsAndConditionsConfirmed')"
/> ></label>
<ds-input </ds-text>
id="about" <ds-space class="backendErrors" v-if="backendErrors">
model="about" <ds-text align="center" bold color="danger">{{ backendErrors.message }}</ds-text>
type="textarea" </ds-space>
rows="3" <ds-button
:label="$t('settings.data.labelBio')" style="float: right;"
:placeholder="$t('settings.data.labelBio')" icon="check"
/> type="submit"
<ds-input :loading="$apollo.loading"
id="password" :disabled="errors || !termsAndConditionsConfirmed"
model="password" primary
type="password" >
autocomplete="off" {{ $t('actions.save') }}
:label="$t('settings.security.change-password.label-new-password')" </ds-button>
/> </template>
<ds-input </ds-form>
id="passwordConfirmation" </div>
model="passwordConfirmation"
type="password"
autocomplete="off"
:label="$t('settings.security.change-password.label-new-password-confirm')"
/>
<password-strength :password="formData.password" />
<ds-text>
<input
id="checkbox"
type="checkbox"
v-model="termsAndConditionsConfirmed"
:checked="termsAndConditionsConfirmed"
/>
<label
for="checkbox"
v-html="$t('termsAndConditions.termsAndConditionsConfirmed')"
></label>
</ds-text>
</ds-flex-item>
<ds-flex-item width="100%">
<ds-space class="backendErrors" v-if="backendErrors">
<ds-text align="center" bold color="danger">{{ backendErrors.message }}</ds-text>
</ds-space>
<ds-button
style="float: right;"
icon="check"
type="submit"
:loading="$apollo.loading"
:disabled="errors || !termsAndConditionsConfirmed"
primary
>
{{ $t('actions.save') }}
</ds-button>
</ds-flex-item>
</ds-flex>
</template>
</ds-form>
</ds-card>
</ds-container>
</template> </template>
<script> <script>
@ -101,13 +81,11 @@ import { SweetalertIcon } from 'vue-sweetalert-icons'
import PasswordForm from '~/components/utils/PasswordFormHelper' import PasswordForm from '~/components/utils/PasswordFormHelper'
import { VERSION } from '~/constants/terms-and-conditions-version.js' import { VERSION } from '~/constants/terms-and-conditions-version.js'
import { SignupVerificationMutation } from '~/graphql/Registration.js' import { SignupVerificationMutation } from '~/graphql/Registration.js'
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
export default { export default {
components: { components: {
PasswordStrength, PasswordStrength,
SweetalertIcon, SweetalertIcon,
LocaleSwitch,
}, },
data() { data() {
const passwordForm = PasswordForm({ translate: this.$t }) const passwordForm = PasswordForm({ translate: this.$t })

View File

@ -69,15 +69,18 @@ describe('Signup', () => {
}) })
it('displays a message that a mail for email verification was sent', () => { it('displays a message that a mail for email verification was sent', () => {
const expected = ['registration.signup.form.success', { email: 'mail@example.org' }] const expected = [
'components.registration.signup.form.success',
{ email: 'mail@example.org' },
]
expect(mocks.$t).toHaveBeenCalledWith(...expected) expect(mocks.$t).toHaveBeenCalledWith(...expected)
}) })
describe('after animation', () => { describe('after animation', () => {
beforeEach(jest.runAllTimers) beforeEach(jest.runAllTimers)
it('emits `handleSubmitted`', () => { it('emits `submit`', () => {
expect(wrapper.emitted('handleSubmitted')).toEqual([[{ email: 'mail@example.org' }]]) expect(wrapper.emitted('submit')).toEqual([[{ email: 'mail@example.org' }]])
}) })
}) })
}) })
@ -121,7 +124,9 @@ describe('Signup', () => {
it('explains the error', async () => { it('explains the error', async () => {
await action() await action()
expect(mocks.$t).toHaveBeenCalledWith('registration.signup.form.errors.email-exists') expect(mocks.$t).toHaveBeenCalledWith(
'components.registration.signup.form.errors.email-exists',
)
}) })
}) })
@ -137,7 +142,7 @@ describe('Signup', () => {
it('explains the error', async () => { it('explains the error', async () => {
await action() await action()
expect(mocks.$t).toHaveBeenCalledWith( expect(mocks.$t).toHaveBeenCalledWith(
'registration.signup.form.errors.invalid-invitation-token', 'components.registration.signup.form.errors.invalid-invitation-token',
) )
}) })
}) })

View File

@ -1,7 +1,6 @@
<template> <template>
<ds-space margin="large"> <ds-space v-if="!success && !error" margin="large">
<ds-form <ds-form
v-if="!success && !error"
@input="handleInput" @input="handleInput"
@input-valid="handleInputValid" @input-valid="handleInputValid"
v-model="formData" v-model="formData"
@ -42,18 +41,19 @@
> >
{{ $t('components.registration.signup.form.submit') }} {{ $t('components.registration.signup.form.submit') }}
</ds-button> </ds-button>
<slot></slot>
</ds-form> </ds-form>
<div v-else>
<template v-if="!error">
<sweetalert-icon icon="info" />
<ds-text align="center" v-html="submitMessage" />
</template>
<template v-else>
<sweetalert-icon icon="error" />
<ds-text align="center">{{ error.message }}</ds-text>
</template>
</div>
</ds-space> </ds-space>
<div v-else margin="large">
<template v-if="!error">
<sweetalert-icon icon="info" />
<ds-text align="center" v-html="submitMessage" />
</template>
<template v-else>
<sweetalert-icon icon="error" />
<ds-text align="center">{{ error.message }}</ds-text>
</template>
</div>
</template> </template>
<script> <script>
@ -103,7 +103,7 @@ export default {
computed: { computed: {
submitMessage() { submitMessage() {
const { email } = this.formData const { email } = this.formData
return this.$t('registration.signup.form.success', { email }) return this.$t('components.registration.signup.form.success', { email })
}, },
}, },
methods: { methods: {
@ -123,7 +123,7 @@ export default {
this.success = true this.success = true
setTimeout(() => { setTimeout(() => {
this.$emit('handleSubmitted', { email }) this.$emit('submit', { email })
}, 3000) }, 3000)
} catch (err) { } catch (err) {
const { message } = err const { message } = err
@ -133,7 +133,10 @@ export default {
} }
for (const [pattern, key] of Object.entries(mapping)) { for (const [pattern, key] of Object.entries(mapping)) {
if (message.includes(pattern)) if (message.includes(pattern))
this.error = { key, message: this.$t(`registration.signup.form.errors.${key}`) } this.error = {
key,
message: this.$t(`components.registration.signup.form.errors.${key}`),
}
} }
if (!this.error) { if (!this.error) {
this.$toast.error(message) this.$toast.error(message)

View File

@ -1,9 +1,29 @@
<template> <template>
<nuxt-child /> <ds-container width="medium">
<ds-card>
<ds-flex gutter="small">
<ds-flex-item :width="{ base: '100%', sm: '50%' }">
<client-only>
<locale-switch offset="5" />
</client-only>
<ds-space margin-top="small" margin-bottom="xxx-small">
<img class="signup-image" alt="Human Connection" src="/img/sign-up/nicetomeetyou.svg" />
</ds-space>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
<nuxt-child />
</ds-flex-item>
</ds-flex>
</ds-card>
</ds-container>
</template> </template>
<script> <script>
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
export default { export default {
components: {
LocaleSwitch,
},
layout: 'no-header', layout: 'no-header',
asyncData({ store, redirect }) { asyncData({ store, redirect }) {
if (store.getters['auth/isLoggedIn']) { if (store.getters['auth/isLoggedIn']) {

View File

@ -1,7 +1,25 @@
<template> <template>
<h1>Enter nonce</h1> <enter-nonce :email="email" @nonceEntered="nonceEntered">
<ds-space margin-bottom="xxx-small" margin-top="large" centered>
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</ds-space>
</enter-nonce>
</template> </template>
<script> <script>
export default {} import EnterNonce from '~/components/EnterNonce/EnterNonce.vue'
export default {
components: {
EnterNonce,
},
data() {
const { email = '' } = this.$route.query
return { email }
},
methods: {
nonceEntered({ email, nonce }) {
this.$router.push({ path: 'create-user-account', query: { email, nonce } })
},
},
}
</script> </script>

View File

@ -1,33 +1,23 @@
<template> <template>
<ds-container width="medium"> <signup :invitation="false" @submit="handleSubmitted">
<ds-card> <ds-space centered margin-top="large">
<ds-flex gutter="small"> <nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered> </ds-space>
<client-only> </signup>
<locale-switch offset="5" />
</client-only>
<ds-space margin-top="small" margin-bottom="xxx-small" centered>
<img class="signup-image" alt="Human Connection" src="/img/sign-up/nicetomeetyou.svg" />
</ds-space>
</ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: '50%' }" centered>
<signup :invitation="false" />
<nuxt-link to="/login">{{ $t('site.back-to-login') }}</nuxt-link>
</ds-flex-item>
</ds-flex>
</ds-card>
</ds-container>
</template> </template>
<script> <script>
import Signup from '~/components/Registration/Signup' import Signup from '~/components/Registration/Signup'
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
export default { export default {
layout: 'no-header', layout: 'no-header',
components: { components: {
Signup, Signup,
LocaleSwitch, },
methods: {
handleSubmitted({ email }) {
this.$router.push({ path: 'enter-nonce', query: { email } })
},
}, },
} }
</script> </script>