Replace old vee-validate version and rewrite the usages
This commit is contained in:
parent
52caced8b0
commit
31f3145cbd
|
|
@ -270,3 +270,8 @@ Command:
|
|||
```
|
||||
./bin/pg-backup-to-s3
|
||||
```
|
||||
|
||||
|
||||
# Note on component
|
||||
Our own components remain in kebap-case, imported components from third party libraries will be used in PascalCase.
|
||||
E.g. `<password-change-form/>` vs. `<ValidationProvider/>`
|
||||
|
|
|
|||
|
|
@ -2209,6 +2209,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@vue/composition-api": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/composition-api/-/composition-api-1.4.2.tgz",
|
||||
"integrity": "sha512-EqybqmMq835GISvlQXdDaV8dsbunpdmhClrnAqUJZLyxxV9pQXQYRtNDf+0e+fEwMfimLIsv7YmbKCbqxGRqXg==",
|
||||
"requires": {
|
||||
"tslib": "^2.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/test-utils": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.2.2.tgz",
|
||||
|
|
@ -19743,9 +19758,9 @@
|
|||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
},
|
||||
"vee-validate": {
|
||||
"version": "2.2.15",
|
||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-2.2.15.tgz",
|
||||
"integrity": "sha512-4TOsI8XwVkKVLkg8Nhmy+jyoJrR6XcTRDyxBarzcCvYzU61zamipS1WsB6FlDze8eJQpgglS4NXAS6o4NDPs1g=="
|
||||
"version": "3.4.14",
|
||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-3.4.14.tgz",
|
||||
"integrity": "sha512-Hqqic8G9WcRSIzCxiCPqMZv4qB8JE1lIQqIOLDm2K5BXUiL8d4a2+kqkanv8gQSGDzYpnCQZ7BO/T99Aj05T1Q=="
|
||||
},
|
||||
"vendors": {
|
||||
"version": "1.0.4",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
"@babel/preset-stage-2": "^7.0.0",
|
||||
"@babel/runtime": "^7.5.4",
|
||||
"@iam4x/cypress-graphql-mock": "0.0.1",
|
||||
"@vue/composition-api": "^1.4.2",
|
||||
"apollo-cache-inmemory": "^1.6.5",
|
||||
"apollo-client": "^2.6.8",
|
||||
"apollo-link": "^1.2.13",
|
||||
|
|
@ -84,16 +85,16 @@
|
|||
"uploadcare-widget": "^3.6.0",
|
||||
"url-loader": "^1.0.1",
|
||||
"uuid": "^3.2.1",
|
||||
"vee-validate": "^2.2.15",
|
||||
"vee-validate": "^3.4.14",
|
||||
"vue": "^2.6.14",
|
||||
"vue-analytics": "^5.16.2",
|
||||
"vue-apollo": "^3.0.0-beta.16",
|
||||
"vue-loader": "^15.9.8",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue-matomo": "^3.13.4-0",
|
||||
"vue-router": "^3.0.1",
|
||||
"vue-scrollto": "^2.11.0",
|
||||
"vue-style-loader": "^3.0.1",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue-toast-notification": "^0.4.1",
|
||||
"vue-vimeo-player": "0.0.6",
|
||||
"vuejs-logger": "1.5.5",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<button
|
||||
:disabled="loading"
|
||||
:disabled="loading || disabled"
|
||||
class="loading-button button button--primary button--big">
|
||||
<template v-if="!loading">{{ label }}</template>
|
||||
<loading-icon
|
||||
|
|
@ -18,6 +18,10 @@
|
|||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
|
|
@ -30,7 +34,7 @@
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_helpers.scss";
|
||||
@import "~styles/helpers";
|
||||
|
||||
.loading-button {
|
||||
height: 52px;
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
<template>
|
||||
<!-- Not currently in use, but keeping the file in case it's needed again -->
|
||||
<div class="password-reset">
|
||||
<h2 class="password-reset__header">Passwort ändern</h2>
|
||||
<div
|
||||
class="success-message"
|
||||
v-if="showSuccess">
|
||||
<p
|
||||
class="success-message__msg"
|
||||
data-cy="password-change-success">Dein Password wurde erfolgreich geändert.</p>
|
||||
</div>
|
||||
<password-change-form
|
||||
:old-password-errors="oldPasswordErrors"
|
||||
:new-password-errors="newPasswordErrors"
|
||||
@passwordSubmited="resetPassword"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import UPDATE_PASSWORD_MUTATION from '@/graphql/gql/mutations/updatePassword.gql';
|
||||
import PasswordChangeForm from '@/components/profile/PasswordChangeForm';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PasswordChangeForm
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
oldPasswordErrors: [],
|
||||
newPasswordErrors: [],
|
||||
showSuccess: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetPassword(passwords) {
|
||||
this.$apollo.mutate({
|
||||
mutation: UPDATE_PASSWORD_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
passwordInput: passwords
|
||||
}
|
||||
}
|
||||
}).then(({data}) => {
|
||||
if (data.updatePassword.success) {
|
||||
this.oldPasswordErrors = [];
|
||||
this.newPasswordErrors = [];
|
||||
this.showSuccess = true;
|
||||
this.$root.$emit('reset-password-form');
|
||||
} else {
|
||||
// currently we just have one error per field
|
||||
const error = data.updatePassword.errors[0];
|
||||
if (error.field === 'old_password') {
|
||||
this.handleOldPasswordError(error);
|
||||
} else {
|
||||
this.handleNewPasswordError(error);
|
||||
}
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log('fail', error);
|
||||
});
|
||||
},
|
||||
handleOldPasswordError(error) {
|
||||
this.oldPasswordErrors = error.errors.map((fieldError) => {
|
||||
if (fieldError.code === 'invalid') {
|
||||
return 'Die Eingabe ist falsch';
|
||||
}
|
||||
});
|
||||
},
|
||||
handleNewPasswordError(error) {
|
||||
this.newPasswordErrors = error.errors.map((fieldError) => {
|
||||
if (fieldError.code === 'invalid') {
|
||||
return 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten';
|
||||
} else if (fieldError.code === 'min_length') {
|
||||
return 'Das Passwort muss mindestens 8 Zeichen lang sein.';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
|
||||
.success-message {
|
||||
margin-bottom: 20px;
|
||||
|
||||
&__msg {
|
||||
color: $color-accent-4-dark;
|
||||
font-family: $sans-serif-font-family;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
<template>
|
||||
<div class="pw-change">
|
||||
<form
|
||||
class="pw-change__form change-form"
|
||||
novalidate
|
||||
@submit.prevent="validateBeforeSubmit">
|
||||
<div class="change-form__field skillboxform-input">
|
||||
<label
|
||||
for="old-pw"
|
||||
class="skillboxform-input__label">Aktuelles Passwort</label>
|
||||
<input
|
||||
v-model="oldPassword"
|
||||
v-validate="'required'"
|
||||
:class="{ 'skillboxform-input__input--error': errors.has('oldPassword') }"
|
||||
name="oldPassword"
|
||||
type="text"
|
||||
class="change-form__old skillbox-input skillboxform-input__input"
|
||||
autocomplete="off"
|
||||
data-vv-as="Altes Passwort"
|
||||
data-cy="old-password"
|
||||
id="old-pw">
|
||||
<small
|
||||
class="skillboxform-input__error"
|
||||
data-cy="old-password-local-errors"
|
||||
v-if="errors.has('oldPassword') && submitted">{{ errors.first('oldPassword') }}</small>
|
||||
<small
|
||||
:key="error"
|
||||
class=" skillboxform-input__error"
|
||||
data-cy="old-password-remote-errors"
|
||||
v-for="error in oldPasswordErrors">{{ error }}</small>
|
||||
</div>
|
||||
<div class="change-form__field skillboxform-input">
|
||||
<label
|
||||
for="new-pw"
|
||||
class="skillboxform-input__label">Neues Passwort</label>
|
||||
<input
|
||||
v-model="newPassword"
|
||||
v-validate="'required|min:8|strongPassword'"
|
||||
:class="{ 'skillboxform-input__input--error': errors.has('newPassword') }"
|
||||
name="newPassword"
|
||||
type="text"
|
||||
data-vv-as="Neues Passwort"
|
||||
class="change-form__new skillbox-input skillboxform-input__input"
|
||||
autocomplete="off"
|
||||
data-cy="new-password"
|
||||
id="new-pw">
|
||||
<small
|
||||
class=" skillboxform-input__error"
|
||||
data-cy="new-password-local-errors"
|
||||
v-if="errors.has('newPassword') && submitted">{{ errors.first('newPassword') }}</small>
|
||||
<small
|
||||
:key="error"
|
||||
class=" skillboxform-input__error"
|
||||
data-cy="new-password-remote-errors"
|
||||
v-for="error in newPasswordErrors">{{ error }}</small>
|
||||
<p class="skillboxform-input__hint">Das Passwort muss mindestens 8 Zeichen lang sein und Grossbuchstaben, Zahlen und Sonderzeichen beinhalten.</p>
|
||||
</div>
|
||||
<button
|
||||
class="button button--primary change-form__submit"
|
||||
data-cy="change-password-button">Speichern</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['newPasswordErrors', 'oldPasswordErrors'],
|
||||
data: () => ({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
submitted: false
|
||||
}),
|
||||
mounted() {
|
||||
this.$root.$on('reset-password-form', () => {
|
||||
this.resetForm();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
validateBeforeSubmit () {
|
||||
this.$validator.validate().then((result) => {
|
||||
this.submitted = true;
|
||||
if (result) {
|
||||
this.$emit('passwordSubmited', {
|
||||
oldPassword: this.oldPassword,
|
||||
newPassword: this.newPassword
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
resetForm () {
|
||||
this.oldPassword = '';
|
||||
this.newPassword = '';
|
||||
this.submitted = false;
|
||||
this.$validator.reset();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_buttons.scss";
|
||||
|
||||
.change-form {
|
||||
width: 50%;
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -7,10 +7,8 @@ import App from './App';
|
|||
import {router, postLoginRedirectUrlKey} from './router';
|
||||
import store from '@/store/index';
|
||||
import VueScrollTo from 'vue-scrollto';
|
||||
import {Validator} from 'vee-validate/dist/vee-validate.minimal.esm.js';
|
||||
import VeeValidate from 'vee-validate';
|
||||
import {required, min, decimal, confirmed} from 'vee-validate/dist/rules.esm.js';
|
||||
import veeDe from 'vee-validate/dist/locale/de';
|
||||
import {extend, localize} from 'vee-validate';
|
||||
import {required, min, double, confirmed} from 'vee-validate/dist/rules';
|
||||
import {dateFilter, dateTimeFilter} from './filters/date-filter';
|
||||
import autoGrow from '@/directives/auto-grow';
|
||||
import clickOutside from '@/directives/click-outside';
|
||||
|
|
@ -20,6 +18,7 @@ import VueRemoveEdges from '@/plugins/edges';
|
|||
import VueMatomo from 'vue-matomo';
|
||||
import VueToast from 'vue-toast-notification';
|
||||
import VueLogger from 'vuejs-logger';
|
||||
import de from 'vee-validate/dist/locale/de.json';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
|
@ -63,28 +62,36 @@ const apolloProvider = new VueApollo({
|
|||
defaultClient: privateApolloClient
|
||||
});
|
||||
|
||||
Validator.extend('required', required);
|
||||
Validator.extend('min', min);
|
||||
Validator.extend('decimal', decimal);
|
||||
Validator.extend('confirmed', confirmed);
|
||||
extend('required', required);
|
||||
extend('min', min);
|
||||
extend('decimal', double);
|
||||
extend('confirmed', confirmed);
|
||||
|
||||
const dict = {
|
||||
custom: {
|
||||
oldPassword: {
|
||||
required: 'Dein aktuelles Passwort fehlt'
|
||||
},
|
||||
newPassword: {
|
||||
required: 'Dein neues Passwort fehlt',
|
||||
min: 'Das neue Passwort muss mindestens 8 Zeichen lang sein'
|
||||
// const dict = {
|
||||
// custom: {
|
||||
// oldPassword: {
|
||||
// required: 'Dein aktuelles Passwort fehlt'
|
||||
// },
|
||||
// newPassword: {
|
||||
// required: 'Dein neues Passwort fehlt',
|
||||
// min: 'Das neue Passwort muss mindestens 8 Zeichen lang sein'
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
localize('de', {
|
||||
de: {
|
||||
...de,
|
||||
names: {
|
||||
password: 'Password',
|
||||
email: 'E-Mail',
|
||||
coupon: 'Coupon'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Validator.localize('de', veeDe);
|
||||
Validator.localize('de', dict);
|
||||
});
|
||||
|
||||
// https://github.com/baianat/vee-validate/issues/51
|
||||
Validator.extend('strongPassword', {
|
||||
extend('strongPassword', {
|
||||
getMessage: field => 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten und mindestens 8 Zeichen lang sein',
|
||||
validate: value => {
|
||||
const strongRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*?(),.":{}|<>+])(?=.{8,})/;
|
||||
|
|
@ -92,7 +99,7 @@ Validator.extend('strongPassword', {
|
|||
}
|
||||
});
|
||||
|
||||
Validator.extend('email', {
|
||||
extend('email', {
|
||||
getMessage: field => 'Bitte geben Sie eine gülitge E-Mail an',
|
||||
validate: value => {
|
||||
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
|
||||
|
|
@ -100,10 +107,6 @@ Validator.extend('email', {
|
|||
}
|
||||
});
|
||||
|
||||
Vue.use(VeeValidate, {
|
||||
locale: 'de'
|
||||
});
|
||||
|
||||
Vue.filter('date', dateFilter);
|
||||
Vue.filter('datetime', dateTimeFilter);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,175 +1,137 @@
|
|||
<template>
|
||||
<div class="login public-page">
|
||||
<h1 class="login__title public-page__title">Melden Sie sich jetzt an</h1>
|
||||
<form
|
||||
class="login__form login-form"
|
||||
novalidate
|
||||
@submit.prevent="validateBeforeSubmit">
|
||||
<div class="login-form__field skillboxform-input">
|
||||
<label
|
||||
for="email"
|
||||
class="skillboxform-input__label">E-Mail</label>
|
||||
<input
|
||||
<ValidationObserver v-slot="{invalid, handleSubmit}">
|
||||
<form
|
||||
class="login__form login-form"
|
||||
novalidate
|
||||
@submit.prevent="handleSubmit(validateBeforeSubmit)">
|
||||
|
||||
<validated-input
|
||||
v-model="email"
|
||||
v-validate="'required'"
|
||||
:class="{ 'skillboxform-input__input--error': errors.has('email') }"
|
||||
:remote-errors="emailErrors"
|
||||
rules="required"
|
||||
name="email"
|
||||
type="text"
|
||||
data-vv-as="E-Mail"
|
||||
class="change-form__email skillbox-input skillboxform-input__input"
|
||||
autocomplete="off"
|
||||
label="E-Mail"
|
||||
data-cy="email-input"
|
||||
id="email"
|
||||
>
|
||||
<small
|
||||
class="skillboxform-input__error"
|
||||
data-cy="email-local-errors"
|
||||
v-if="errors.has('email') && submitted"
|
||||
>{{ errors.first('email') }}</small>
|
||||
<small
|
||||
:key="error"
|
||||
class="skillboxform-input__error"
|
||||
data-cy="email-remote-errors"
|
||||
v-for="error in emailErrors"
|
||||
>{{ error }}</small>
|
||||
</div>
|
||||
<div class="change-form__field skillboxform-input">
|
||||
<label
|
||||
for="pw"
|
||||
class="skillboxform-input__label">Passwort</label>
|
||||
<input
|
||||
/>
|
||||
|
||||
<validated-input
|
||||
v-slot="{errors}"
|
||||
v-model="password"
|
||||
v-validate="'required'"
|
||||
:class="{ 'skillboxform-input__input--error': errors.has('password') }"
|
||||
:remote-errors="passwordErrors"
|
||||
label="Passwort"
|
||||
rules="required"
|
||||
name="password"
|
||||
type="password"
|
||||
data-vv-as="Passwort"
|
||||
class="change-form__new skillbox-input skillboxform-input__input"
|
||||
autocomplete="off"
|
||||
data-cy="password-input"
|
||||
id="pw"
|
||||
>
|
||||
<small
|
||||
class="skillboxform-input__error"
|
||||
data-cy="password-local-errors"
|
||||
v-if="errors.has('password') && submitted"
|
||||
>{{ errors.first('password') }}</small>
|
||||
<small
|
||||
:key="error"
|
||||
class="skillboxform-input__error"
|
||||
data-cy="password-remote-errors"
|
||||
v-for="error in passwordErrors"
|
||||
>{{ error }}</small>
|
||||
</div>
|
||||
<div class="skillboxform-input">
|
||||
<small
|
||||
class="skillboxform-input__error"
|
||||
data-cy="login-error"
|
||||
v-if="loginError">{{ loginError }}</small>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button
|
||||
class="button button--primary button--big actions__submit"
|
||||
data-cy="login-button">Anmelden</button>
|
||||
</div>
|
||||
</form>
|
||||
/>
|
||||
|
||||
<div class="skillboxform-input">
|
||||
<small
|
||||
class="skillboxform-input__error"
|
||||
data-cy="login-error"
|
||||
v-if="loginError">{{ loginError }}</small>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button
|
||||
:disabled="invalid"
|
||||
class="button button--primary button--big actions__submit"
|
||||
data-cy="login-button">Anmelden
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BETA_LOGIN_MUTATION from '@/graphql/gql/mutations/betaLogin.gql';
|
||||
import BETA_LOGIN_MUTATION from '@/graphql/gql/mutations/betaLogin.gql';
|
||||
import {ValidationObserver, ValidationProvider} from 'vee-validate';
|
||||
import ValidatedInput from '@/components/validation/ValidatedInput';
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
emailErrors: [],
|
||||
passwordErrors: [],
|
||||
loginError: '',
|
||||
submitted: false
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
validateBeforeSubmit() {
|
||||
this.$validator.validate().then(result => {
|
||||
this.submitted = true;
|
||||
let that = this;
|
||||
if (result) {
|
||||
this.$apollo.mutate({
|
||||
client: 'publicClient',
|
||||
mutation: BETA_LOGIN_MUTATION,
|
||||
variables: {
|
||||
input: {
|
||||
usernameInput: this.email,
|
||||
passwordInput: this.password
|
||||
}
|
||||
},
|
||||
update(
|
||||
store,
|
||||
{
|
||||
data: {
|
||||
betaLogin
|
||||
}
|
||||
}
|
||||
) {
|
||||
try {
|
||||
if (betaLogin.success) {
|
||||
const redirectUrl = that.$route.query.redirect ? that.$route.query.redirect : '/';
|
||||
that.$router.push(redirectUrl);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
that.loginError = 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie nochmals.';
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
const firstError = error.graphQLErrors[0];
|
||||
switch (firstError.message) {
|
||||
case 'invalid_credentials':
|
||||
that.loginError = 'Die E-Mail oder das Passwort ist falsch. Bitte versuchen Sie nochmals.';
|
||||
break;
|
||||
case 'license_inactive':
|
||||
that.loginError = 'Ihre Lizenz ist nicht mehr aktiv.';
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
export default {
|
||||
components: {
|
||||
ValidatedInput,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
},
|
||||
resetForm() {
|
||||
this.email = '';
|
||||
this.password = '';
|
||||
this.submitted = false;
|
||||
this.$validator.reset();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
emailErrors: [],
|
||||
passwordErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
validateBeforeSubmit() {
|
||||
this.submitted = true;
|
||||
|
||||
const variables = {
|
||||
input: {
|
||||
usernameInput: this.email,
|
||||
passwordInput: this.password,
|
||||
},
|
||||
};
|
||||
|
||||
const redirectUrl = this.$route.query.redirect ? this.$route.query.redirect : '/';
|
||||
|
||||
this.$apollo.mutate({
|
||||
client: 'publicClient',
|
||||
mutation: BETA_LOGIN_MUTATION,
|
||||
variables,
|
||||
update: (store, {data: {betaLogin}}) => {
|
||||
try {
|
||||
if (betaLogin.success) {
|
||||
console.log(this);
|
||||
this.$router.push(redirectUrl);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
this.loginError = 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie nochmals.';
|
||||
}
|
||||
},
|
||||
}).catch(error => {
|
||||
const firstError = error.graphQLErrors[0];
|
||||
switch (firstError.message) {
|
||||
case 'invalid_credentials':
|
||||
this.loginError = 'Die E-Mail oder das Passwort ist falsch. Bitte versuchen Sie nochmals.';
|
||||
break;
|
||||
case 'license_inactive':
|
||||
this.loginError = 'Ihre Lizenz ist nicht mehr aktiv.';
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
@import "~styles/helpers";
|
||||
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
padding: 15px;
|
||||
line-height: 19px;
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
padding: 15px;
|
||||
line-height: 19px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,57 +1,44 @@
|
|||
<template>
|
||||
<div class="license-activation public-page">
|
||||
<header class="info-header">
|
||||
<p class="info-header__text small-emph">Für <span class="info-header__emph">{{ me.email }}</span> haben wir keine gültige Lizenz gefunden</p>
|
||||
<p class="info-header__text small-emph">Für <span class="info-header__emph">{{ me.email }}</span> haben wir keine
|
||||
gültige Lizenz gefunden</p>
|
||||
</header>
|
||||
<section class="coupon">
|
||||
<form
|
||||
class="license-activation__form license-activation-form"
|
||||
novalidate
|
||||
@submit.prevent="validateBeforeSubmit">
|
||||
<h2>Geben Sie einen Coupon-Code ein</h2>
|
||||
<div class="change-form__field skillboxform-input">
|
||||
<label
|
||||
for="coupon"
|
||||
class="skillboxform-input__label">Coupon-Code</label>
|
||||
<input
|
||||
<ValidationObserver
|
||||
v-slot="{handleSubmit, invalid}"
|
||||
>
|
||||
<form
|
||||
class="license-activation__form license-activation-form"
|
||||
novalidate
|
||||
@submit.prevent="handleSubmit(validateBeforeSubmit)">
|
||||
<h2>Geben Sie einen Coupon-Code ein</h2>
|
||||
<validated-input
|
||||
v-model="coupon"
|
||||
v-validate="'required'"
|
||||
:class="{ 'skillboxform-input__input--error': errors.has('coupon') }"
|
||||
:remote-errors="couponErrors"
|
||||
rules="required"
|
||||
name="coupon"
|
||||
type="coupon"
|
||||
data-vv-as="Coupon"
|
||||
class="change-form__new skillbox-input skillboxform-input__input"
|
||||
autocomplete="off"
|
||||
label="Coupon-Code"
|
||||
data-cy="coupon-input"
|
||||
class="login-form__field"
|
||||
tabindex="0"
|
||||
id="coupon"
|
||||
>
|
||||
<small
|
||||
class="skillboxform-input__error"
|
||||
data-cy="coupon-local-errors"
|
||||
v-if="errors.has('coupon') && submitted"
|
||||
>{{ errors.first('coupon') }}</small>
|
||||
<small
|
||||
:key="error"
|
||||
class="skillboxform-input__error"
|
||||
data-cy="coupon-remote-errors"
|
||||
v-for="error in couponErrors"
|
||||
>{{ error }}</small>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<loading-button
|
||||
:loading="loading"
|
||||
class="actions__submit"
|
||||
data-cy="coupon-button"
|
||||
label="Coupon abschicken"
|
||||
/>
|
||||
<a
|
||||
class="button button--big"
|
||||
data-cy="license-activation-cancel"
|
||||
@click="logout">Abmelden
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
<div class="actions">
|
||||
<loading-button
|
||||
:loading="loading"
|
||||
:disabled="invalid"
|
||||
class="actions__submit"
|
||||
data-cy="coupon-button"
|
||||
label="Coupon abschicken"
|
||||
/>
|
||||
<a
|
||||
class="button button--big"
|
||||
data-cy="license-activation-cancel"
|
||||
@click="logout">Abmelden
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</ValidationObserver>
|
||||
</section>
|
||||
<section class="get-license">
|
||||
<h2>Oder, kaufen Sie eine Lizenz</h2>
|
||||
|
|
@ -69,108 +56,103 @@
|
|||
|
||||
<script>
|
||||
|
||||
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import LoadingButton from '@/components/LoadingButton';
|
||||
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
|
||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||
import LoadingButton from '@/components/LoadingButton';
|
||||
import ValidatedInput from '@/components/validation/ValidatedInput';
|
||||
import {ValidationObserver} from 'vee-validate';
|
||||
|
||||
import me from '@/mixins/me';
|
||||
import logout from '@/mixins/logout';
|
||||
import pageTitleMixin from '@/mixins/page-title';
|
||||
import me from '@/mixins/me';
|
||||
import logout from '@/mixins/logout';
|
||||
import pageTitleMixin from '@/mixins/page-title';
|
||||
|
||||
export default {
|
||||
mixins: [me, logout, pageTitleMixin],
|
||||
components: {LoadingButton},
|
||||
export default {
|
||||
mixins: [me, logout, pageTitleMixin],
|
||||
components: {
|
||||
LoadingButton,
|
||||
ValidationObserver,
|
||||
ValidatedInput,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
coupon: '',
|
||||
couponErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
me: {
|
||||
email: ''
|
||||
},
|
||||
teacherEditionUrl: `${process.env.HEP_URL}/myskillbox-lehrpersonen`,
|
||||
studentEditionUrl: `${process.env.HEP_URL}/myskillbox-fur-lernende`,
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
validateBeforeSubmit() {
|
||||
this.$validator.validate().then(result => {
|
||||
data() {
|
||||
return {
|
||||
coupon: '',
|
||||
couponErrors: [],
|
||||
loginError: '',
|
||||
submitted: false,
|
||||
me: {
|
||||
email: '',
|
||||
},
|
||||
teacherEditionUrl: `${process.env.HEP_URL}/myskillbox-lehrpersonen`,
|
||||
studentEditionUrl: `${process.env.HEP_URL}/myskillbox-fur-lernende`,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
validateBeforeSubmit() {
|
||||
this.submitted = true;
|
||||
let that = this;
|
||||
if (result) {
|
||||
this.loading = true;
|
||||
this.$apollo.mutate({
|
||||
mutation: REDEEM_COUPON,
|
||||
variables: {
|
||||
input: {
|
||||
couponCode: this.coupon
|
||||
}
|
||||
this.loading = true;
|
||||
this.$apollo.mutate({
|
||||
mutation: REDEEM_COUPON,
|
||||
variables: {
|
||||
input: {
|
||||
couponCode: this.coupon,
|
||||
},
|
||||
update(
|
||||
store,
|
||||
{
|
||||
data: {coupon}
|
||||
}
|
||||
) {
|
||||
if (coupon.success) {
|
||||
that.loading = false;
|
||||
that.couponErrors = [];
|
||||
that.$apollo.query({
|
||||
query: ME_QUERY,
|
||||
fetchPolicy: 'network-only',
|
||||
}).then(() => that.$router.push('/'));
|
||||
}
|
||||
},
|
||||
update(
|
||||
store,
|
||||
{
|
||||
data: {coupon},
|
||||
},
|
||||
) {
|
||||
if (coupon.success) {
|
||||
this.loading = false;
|
||||
this.couponErrors = [];
|
||||
this.$apollo.query({
|
||||
query: ME_QUERY,
|
||||
fetchPolicy: 'network-only',
|
||||
}).then(() => this.$router.push('/'));
|
||||
}
|
||||
}).catch(({message}) => {
|
||||
},
|
||||
}).catch(({message}) => {
|
||||
this.loading = false;
|
||||
if (message.indexOf('invalid_coupon') > -1) {
|
||||
that.couponErrors = ['Der angegebene Coupon-Code ist ungültig.'];
|
||||
this.couponErrors = ['Der angegebene Coupon-Code ist ungültig.'];
|
||||
} else {
|
||||
that.couponErrors = ['Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.'];
|
||||
this.couponErrors = ['Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.'];
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
resetForm() {
|
||||
this.coupon = '';
|
||||
this.submitted = false;
|
||||
this.$validator.reset();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/styles/_variables.scss";
|
||||
@import "@/styles/_mixins.scss";
|
||||
@import "~styles/helpers";
|
||||
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
}
|
||||
|
||||
.actions {
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
.text-link {
|
||||
font-family: $sans-serif-font-family;
|
||||
color: $color-brand;
|
||||
}
|
||||
}
|
||||
|
||||
.get-license {
|
||||
margin-top: $large-spacing
|
||||
}
|
||||
|
||||
.license-links {
|
||||
&__item {
|
||||
margin-bottom: $medium-spacing;
|
||||
.actions {
|
||||
&__reset {
|
||||
display: inline-block;
|
||||
margin-left: $large-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
.get-license {
|
||||
margin-top: $large-spacing
|
||||
}
|
||||
|
||||
.license-links {
|
||||
&__item {
|
||||
margin-bottom: $medium-spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -12,17 +12,29 @@
|
|||
&--white-bg {
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
@mixin disabled {
|
||||
cursor: default;
|
||||
}
|
||||
&--disabled {
|
||||
@include disabled;
|
||||
@mixin disabled-default {
|
||||
cursor: default;
|
||||
background-color: $color-silver-light;
|
||||
border-color: $color-silver-light;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@include disabled-default;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
@include disabled-default;
|
||||
}
|
||||
|
||||
&--disabled-alt {
|
||||
@include disabled;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&--big {
|
||||
padding: 15px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue