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
|
./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": {
|
"@vue/test-utils": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.2.2.tgz",
|
||||||
|
|
@ -19743,9 +19758,9 @@
|
||||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||||
},
|
},
|
||||||
"vee-validate": {
|
"vee-validate": {
|
||||||
"version": "2.2.15",
|
"version": "3.4.14",
|
||||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-2.2.15.tgz",
|
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-3.4.14.tgz",
|
||||||
"integrity": "sha512-4TOsI8XwVkKVLkg8Nhmy+jyoJrR6XcTRDyxBarzcCvYzU61zamipS1WsB6FlDze8eJQpgglS4NXAS6o4NDPs1g=="
|
"integrity": "sha512-Hqqic8G9WcRSIzCxiCPqMZv4qB8JE1lIQqIOLDm2K5BXUiL8d4a2+kqkanv8gQSGDzYpnCQZ7BO/T99Aj05T1Q=="
|
||||||
},
|
},
|
||||||
"vendors": {
|
"vendors": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
"@babel/preset-stage-2": "^7.0.0",
|
"@babel/preset-stage-2": "^7.0.0",
|
||||||
"@babel/runtime": "^7.5.4",
|
"@babel/runtime": "^7.5.4",
|
||||||
"@iam4x/cypress-graphql-mock": "0.0.1",
|
"@iam4x/cypress-graphql-mock": "0.0.1",
|
||||||
|
"@vue/composition-api": "^1.4.2",
|
||||||
"apollo-cache-inmemory": "^1.6.5",
|
"apollo-cache-inmemory": "^1.6.5",
|
||||||
"apollo-client": "^2.6.8",
|
"apollo-client": "^2.6.8",
|
||||||
"apollo-link": "^1.2.13",
|
"apollo-link": "^1.2.13",
|
||||||
|
|
@ -84,16 +85,16 @@
|
||||||
"uploadcare-widget": "^3.6.0",
|
"uploadcare-widget": "^3.6.0",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.0.1",
|
||||||
"uuid": "^3.2.1",
|
"uuid": "^3.2.1",
|
||||||
"vee-validate": "^2.2.15",
|
"vee-validate": "^3.4.14",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
"vue-analytics": "^5.16.2",
|
"vue-analytics": "^5.16.2",
|
||||||
"vue-apollo": "^3.0.0-beta.16",
|
"vue-apollo": "^3.0.0-beta.16",
|
||||||
"vue-loader": "^15.9.8",
|
"vue-loader": "^15.9.8",
|
||||||
"vue-template-compiler": "^2.6.14",
|
|
||||||
"vue-matomo": "^3.13.4-0",
|
"vue-matomo": "^3.13.4-0",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
"vue-scrollto": "^2.11.0",
|
"vue-scrollto": "^2.11.0",
|
||||||
"vue-style-loader": "^3.0.1",
|
"vue-style-loader": "^3.0.1",
|
||||||
|
"vue-template-compiler": "^2.6.14",
|
||||||
"vue-toast-notification": "^0.4.1",
|
"vue-toast-notification": "^0.4.1",
|
||||||
"vue-vimeo-player": "0.0.6",
|
"vue-vimeo-player": "0.0.6",
|
||||||
"vuejs-logger": "1.5.5",
|
"vuejs-logger": "1.5.5",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
:disabled="loading"
|
:disabled="loading || disabled"
|
||||||
class="loading-button button button--primary button--big">
|
class="loading-button button button--primary button--big">
|
||||||
<template v-if="!loading">{{ label }}</template>
|
<template v-if="!loading">{{ label }}</template>
|
||||||
<loading-icon
|
<loading-icon
|
||||||
|
|
@ -18,6 +18,10 @@
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
|
@ -30,7 +34,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_helpers.scss";
|
@import "~styles/helpers";
|
||||||
|
|
||||||
.loading-button {
|
.loading-button {
|
||||||
height: 52px;
|
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 {router, postLoginRedirectUrlKey} from './router';
|
||||||
import store from '@/store/index';
|
import store from '@/store/index';
|
||||||
import VueScrollTo from 'vue-scrollto';
|
import VueScrollTo from 'vue-scrollto';
|
||||||
import {Validator} from 'vee-validate/dist/vee-validate.minimal.esm.js';
|
import {extend, localize} from 'vee-validate';
|
||||||
import VeeValidate from 'vee-validate';
|
import {required, min, double, confirmed} from 'vee-validate/dist/rules';
|
||||||
import {required, min, decimal, confirmed} from 'vee-validate/dist/rules.esm.js';
|
|
||||||
import veeDe from 'vee-validate/dist/locale/de';
|
|
||||||
import {dateFilter, dateTimeFilter} from './filters/date-filter';
|
import {dateFilter, dateTimeFilter} from './filters/date-filter';
|
||||||
import autoGrow from '@/directives/auto-grow';
|
import autoGrow from '@/directives/auto-grow';
|
||||||
import clickOutside from '@/directives/click-outside';
|
import clickOutside from '@/directives/click-outside';
|
||||||
|
|
@ -20,6 +18,7 @@ import VueRemoveEdges from '@/plugins/edges';
|
||||||
import VueMatomo from 'vue-matomo';
|
import VueMatomo from 'vue-matomo';
|
||||||
import VueToast from 'vue-toast-notification';
|
import VueToast from 'vue-toast-notification';
|
||||||
import VueLogger from 'vuejs-logger';
|
import VueLogger from 'vuejs-logger';
|
||||||
|
import de from 'vee-validate/dist/locale/de.json';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
@ -63,28 +62,36 @@ const apolloProvider = new VueApollo({
|
||||||
defaultClient: privateApolloClient
|
defaultClient: privateApolloClient
|
||||||
});
|
});
|
||||||
|
|
||||||
Validator.extend('required', required);
|
extend('required', required);
|
||||||
Validator.extend('min', min);
|
extend('min', min);
|
||||||
Validator.extend('decimal', decimal);
|
extend('decimal', double);
|
||||||
Validator.extend('confirmed', confirmed);
|
extend('confirmed', confirmed);
|
||||||
|
|
||||||
const dict = {
|
// const dict = {
|
||||||
custom: {
|
// custom: {
|
||||||
oldPassword: {
|
// oldPassword: {
|
||||||
required: 'Dein aktuelles Passwort fehlt'
|
// required: 'Dein aktuelles Passwort fehlt'
|
||||||
},
|
// },
|
||||||
newPassword: {
|
// newPassword: {
|
||||||
required: 'Dein neues Passwort fehlt',
|
// required: 'Dein neues Passwort fehlt',
|
||||||
min: 'Das neue Passwort muss mindestens 8 Zeichen lang sein'
|
// 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
|
// 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',
|
getMessage: field => 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten und mindestens 8 Zeichen lang sein',
|
||||||
validate: value => {
|
validate: value => {
|
||||||
const strongRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*?(),.":{}|<>+])(?=.{8,})/;
|
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',
|
getMessage: field => 'Bitte geben Sie eine gülitge E-Mail an',
|
||||||
validate: value => {
|
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])?)+$/;
|
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('date', dateFilter);
|
||||||
Vue.filter('datetime', dateTimeFilter);
|
Vue.filter('datetime', dateTimeFilter);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,175 +1,137 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login public-page">
|
<div class="login public-page">
|
||||||
<h1 class="login__title public-page__title">Melden Sie sich jetzt an</h1>
|
<h1 class="login__title public-page__title">Melden Sie sich jetzt an</h1>
|
||||||
<form
|
<ValidationObserver v-slot="{invalid, handleSubmit}">
|
||||||
class="login__form login-form"
|
<form
|
||||||
novalidate
|
class="login__form login-form"
|
||||||
@submit.prevent="validateBeforeSubmit">
|
novalidate
|
||||||
<div class="login-form__field skillboxform-input">
|
@submit.prevent="handleSubmit(validateBeforeSubmit)">
|
||||||
<label
|
|
||||||
for="email"
|
<validated-input
|
||||||
class="skillboxform-input__label">E-Mail</label>
|
|
||||||
<input
|
|
||||||
v-model="email"
|
v-model="email"
|
||||||
v-validate="'required'"
|
:remote-errors="emailErrors"
|
||||||
:class="{ 'skillboxform-input__input--error': errors.has('email') }"
|
rules="required"
|
||||||
name="email"
|
name="email"
|
||||||
type="text"
|
label="E-Mail"
|
||||||
data-vv-as="E-Mail"
|
|
||||||
class="change-form__email skillbox-input skillboxform-input__input"
|
|
||||||
autocomplete="off"
|
|
||||||
data-cy="email-input"
|
data-cy="email-input"
|
||||||
id="email"
|
id="email"
|
||||||
>
|
/>
|
||||||
<small
|
|
||||||
class="skillboxform-input__error"
|
<validated-input
|
||||||
data-cy="email-local-errors"
|
v-slot="{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
|
|
||||||
v-model="password"
|
v-model="password"
|
||||||
v-validate="'required'"
|
:remote-errors="passwordErrors"
|
||||||
:class="{ 'skillboxform-input__input--error': errors.has('password') }"
|
label="Passwort"
|
||||||
|
rules="required"
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
type="password"
|
||||||
data-vv-as="Passwort"
|
|
||||||
class="change-form__new skillbox-input skillboxform-input__input"
|
|
||||||
autocomplete="off"
|
|
||||||
data-cy="password-input"
|
data-cy="password-input"
|
||||||
id="pw"
|
/>
|
||||||
>
|
|
||||||
<small
|
<div class="skillboxform-input">
|
||||||
class="skillboxform-input__error"
|
<small
|
||||||
data-cy="password-local-errors"
|
class="skillboxform-input__error"
|
||||||
v-if="errors.has('password') && submitted"
|
data-cy="login-error"
|
||||||
>{{ errors.first('password') }}</small>
|
v-if="loginError">{{ loginError }}</small>
|
||||||
<small
|
</div>
|
||||||
:key="error"
|
<div class="actions">
|
||||||
class="skillboxform-input__error"
|
<button
|
||||||
data-cy="password-remote-errors"
|
:disabled="invalid"
|
||||||
v-for="error in passwordErrors"
|
class="button button--primary button--big actions__submit"
|
||||||
>{{ error }}</small>
|
data-cy="login-button">Anmelden
|
||||||
</div>
|
</button>
|
||||||
<div class="skillboxform-input">
|
</div>
|
||||||
<small
|
</form>
|
||||||
class="skillboxform-input__error"
|
</ValidationObserver>
|
||||||
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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<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 {
|
export default {
|
||||||
components: {},
|
components: {
|
||||||
|
ValidatedInput,
|
||||||
data() {
|
ValidationProvider,
|
||||||
return {
|
ValidationObserver,
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
resetForm() {
|
|
||||||
this.email = '';
|
data() {
|
||||||
this.password = '';
|
return {
|
||||||
this.submitted = false;
|
email: '',
|
||||||
this.$validator.reset();
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
@import "@/styles/_mixins.scss";
|
|
||||||
|
|
||||||
.text-link {
|
.text-link {
|
||||||
font-family: $sans-serif-font-family;
|
font-family: $sans-serif-font-family;
|
||||||
color: $color-brand;
|
color: $color-brand;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
&__reset {
|
&__reset {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: $large-spacing;
|
margin-left: $large-spacing;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
line-height: 19px;
|
line-height: 19px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,44 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="license-activation public-page">
|
<div class="license-activation public-page">
|
||||||
<header class="info-header">
|
<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>
|
</header>
|
||||||
<section class="coupon">
|
<section class="coupon">
|
||||||
<form
|
<ValidationObserver
|
||||||
class="license-activation__form license-activation-form"
|
v-slot="{handleSubmit, invalid}"
|
||||||
novalidate
|
>
|
||||||
@submit.prevent="validateBeforeSubmit">
|
<form
|
||||||
<h2>Geben Sie einen Coupon-Code ein</h2>
|
class="license-activation__form license-activation-form"
|
||||||
<div class="change-form__field skillboxform-input">
|
novalidate
|
||||||
<label
|
@submit.prevent="handleSubmit(validateBeforeSubmit)">
|
||||||
for="coupon"
|
<h2>Geben Sie einen Coupon-Code ein</h2>
|
||||||
class="skillboxform-input__label">Coupon-Code</label>
|
<validated-input
|
||||||
<input
|
|
||||||
v-model="coupon"
|
v-model="coupon"
|
||||||
v-validate="'required'"
|
:remote-errors="couponErrors"
|
||||||
:class="{ 'skillboxform-input__input--error': errors.has('coupon') }"
|
rules="required"
|
||||||
name="coupon"
|
name="coupon"
|
||||||
type="coupon"
|
label="Coupon-Code"
|
||||||
data-vv-as="Coupon"
|
|
||||||
class="change-form__new skillbox-input skillboxform-input__input"
|
|
||||||
autocomplete="off"
|
|
||||||
data-cy="coupon-input"
|
data-cy="coupon-input"
|
||||||
|
class="login-form__field"
|
||||||
tabindex="0"
|
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
|
<div class="actions">
|
||||||
class="button button--big"
|
<loading-button
|
||||||
data-cy="license-activation-cancel"
|
:loading="loading"
|
||||||
@click="logout">Abmelden
|
:disabled="invalid"
|
||||||
</a>
|
class="actions__submit"
|
||||||
</div>
|
data-cy="coupon-button"
|
||||||
</form>
|
label="Coupon abschicken"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
class="button button--big"
|
||||||
|
data-cy="license-activation-cancel"
|
||||||
|
@click="logout">Abmelden
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</ValidationObserver>
|
||||||
</section>
|
</section>
|
||||||
<section class="get-license">
|
<section class="get-license">
|
||||||
<h2>Oder, kaufen Sie eine Lizenz</h2>
|
<h2>Oder, kaufen Sie eine Lizenz</h2>
|
||||||
|
|
@ -69,108 +56,103 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
|
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
|
||||||
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
|
||||||
import LoadingButton from '@/components/LoadingButton';
|
import LoadingButton from '@/components/LoadingButton';
|
||||||
|
import ValidatedInput from '@/components/validation/ValidatedInput';
|
||||||
|
import {ValidationObserver} from 'vee-validate';
|
||||||
|
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
import logout from '@/mixins/logout';
|
import logout from '@/mixins/logout';
|
||||||
import pageTitleMixin from '@/mixins/page-title';
|
import pageTitleMixin from '@/mixins/page-title';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [me, logout, pageTitleMixin],
|
mixins: [me, logout, pageTitleMixin],
|
||||||
components: {LoadingButton},
|
components: {
|
||||||
|
LoadingButton,
|
||||||
|
ValidationObserver,
|
||||||
|
ValidatedInput,
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
coupon: '',
|
coupon: '',
|
||||||
couponErrors: [],
|
couponErrors: [],
|
||||||
loginError: '',
|
loginError: '',
|
||||||
submitted: false,
|
submitted: false,
|
||||||
me: {
|
me: {
|
||||||
email: ''
|
email: '',
|
||||||
},
|
},
|
||||||
teacherEditionUrl: `${process.env.HEP_URL}/myskillbox-lehrpersonen`,
|
teacherEditionUrl: `${process.env.HEP_URL}/myskillbox-lehrpersonen`,
|
||||||
studentEditionUrl: `${process.env.HEP_URL}/myskillbox-fur-lernende`,
|
studentEditionUrl: `${process.env.HEP_URL}/myskillbox-fur-lernende`,
|
||||||
loading: false
|
loading: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
validateBeforeSubmit() {
|
validateBeforeSubmit() {
|
||||||
this.$validator.validate().then(result => {
|
|
||||||
this.submitted = true;
|
this.submitted = true;
|
||||||
let that = this;
|
this.loading = true;
|
||||||
if (result) {
|
this.$apollo.mutate({
|
||||||
this.loading = true;
|
mutation: REDEEM_COUPON,
|
||||||
this.$apollo.mutate({
|
variables: {
|
||||||
mutation: REDEEM_COUPON,
|
input: {
|
||||||
variables: {
|
couponCode: this.coupon,
|
||||||
input: {
|
|
||||||
couponCode: this.coupon
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
update(
|
},
|
||||||
store,
|
update(
|
||||||
{
|
store,
|
||||||
data: {coupon}
|
{
|
||||||
}
|
data: {coupon},
|
||||||
) {
|
},
|
||||||
if (coupon.success) {
|
) {
|
||||||
that.loading = false;
|
if (coupon.success) {
|
||||||
that.couponErrors = [];
|
this.loading = false;
|
||||||
that.$apollo.query({
|
this.couponErrors = [];
|
||||||
query: ME_QUERY,
|
this.$apollo.query({
|
||||||
fetchPolicy: 'network-only',
|
query: ME_QUERY,
|
||||||
}).then(() => that.$router.push('/'));
|
fetchPolicy: 'network-only',
|
||||||
}
|
}).then(() => this.$router.push('/'));
|
||||||
}
|
}
|
||||||
}).catch(({message}) => {
|
},
|
||||||
|
}).catch(({message}) => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (message.indexOf('invalid_coupon') > -1) {
|
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 {
|
} 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(() => {
|
.finally(() => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
|
||||||
},
|
},
|
||||||
resetForm() {
|
};
|
||||||
this.coupon = '';
|
|
||||||
this.submitted = false;
|
|
||||||
this.$validator.reset();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
@import "@/styles/_mixins.scss";
|
|
||||||
|
|
||||||
.text-link {
|
.text-link {
|
||||||
font-family: $sans-serif-font-family;
|
font-family: $sans-serif-font-family;
|
||||||
color: $color-brand;
|
color: $color-brand;
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
&__reset {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: $large-spacing;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.get-license {
|
.actions {
|
||||||
margin-top: $large-spacing
|
&__reset {
|
||||||
}
|
display: inline-block;
|
||||||
|
margin-left: $large-spacing;
|
||||||
.license-links {
|
}
|
||||||
&__item {
|
}
|
||||||
margin-bottom: $medium-spacing;
|
|
||||||
|
.get-license {
|
||||||
|
margin-top: $large-spacing
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-links {
|
||||||
|
&__item {
|
||||||
|
margin-bottom: $medium-spacing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,29 @@
|
||||||
&--white-bg {
|
&--white-bg {
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin disabled {
|
@mixin disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
&--disabled {
|
@mixin disabled-default {
|
||||||
@include disabled;
|
cursor: default;
|
||||||
background-color: $color-silver-light;
|
background-color: $color-silver-light;
|
||||||
|
border-color: $color-silver-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
@include disabled-default;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
@include disabled-default;
|
||||||
|
}
|
||||||
|
|
||||||
&--disabled-alt {
|
&--disabled-alt {
|
||||||
@include disabled;
|
@include disabled;
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--big {
|
&--big {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue