Better styling for client-side validation. Add I18n for validation errors.
This commit is contained in:
parent
2b903f790d
commit
f9ff839b1a
5 changed files with 85 additions and 23 deletions
|
@ -1,5 +1,5 @@
|
||||||
import { validationMixin } from 'vuelidate'
|
import { validationMixin } from 'vuelidate'
|
||||||
import { required } from 'vuelidate/lib/validators'
|
import { required, sameAs, email } from 'vuelidate/lib/validators'
|
||||||
import { mapActions, mapState } from 'vuex'
|
import { mapActions, mapState } from 'vuex'
|
||||||
import { SIGN_UP } from '../../mutation_types'
|
import { SIGN_UP } from '../../mutation_types'
|
||||||
|
|
||||||
|
@ -16,24 +16,29 @@ const registration = {
|
||||||
}),
|
}),
|
||||||
validations: {
|
validations: {
|
||||||
user: {
|
user: {
|
||||||
email: { required },
|
email: { required, email },
|
||||||
username: { required },
|
username: { required },
|
||||||
password: { required },
|
password: { required },
|
||||||
confirm: { required }
|
confirm: {
|
||||||
|
required,
|
||||||
|
sameAsPassword: sameAs('password')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
if ((!this.$store.state.instance.registrationOpen && !this.token) || !!this.$store.state.users.currentUser) {
|
if ((!this.registrationOpen && !this.token) || this.signedIn) {
|
||||||
this.$router.push('/main/all')
|
this.$router.push('/main/all')
|
||||||
}
|
}
|
||||||
// Seems like this doesn't work at first page open for some reason
|
// // Seems like this doesn't work at first page open for some reason
|
||||||
if (this.$store.state.instance.registrationOpen && this.token) {
|
// if (this.$store.state.instance.registrationOpen && this.token) {
|
||||||
this.$router.push('/registration')
|
// this.$router.push('/registration')
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
token () { return this.$route.params.token },
|
token () { return this.$route.params.token },
|
||||||
...mapState({
|
...mapState({
|
||||||
|
registrationOpen: (state) => state.instance.registrationOpen,
|
||||||
|
signedIn: (state) => !!state.users.currentUser,
|
||||||
isPending: (state) => state.users[SIGN_UP.isPending],
|
isPending: (state) => state.users[SIGN_UP.isPending],
|
||||||
serverValidationErrors: (state) => state.users[SIGN_UP.errors],
|
serverValidationErrors: (state) => state.users[SIGN_UP.errors],
|
||||||
termsofservice: (state) => state.instance.tos
|
termsofservice: (state) => state.instance.tos
|
||||||
|
@ -41,14 +46,19 @@ const registration = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['signUp']),
|
...mapActions(['signUp']),
|
||||||
submit () {
|
async submit () {
|
||||||
this.user.nickname = this.user.username
|
this.user.nickname = this.user.username
|
||||||
this.user.token = this.token
|
this.user.token = this.token
|
||||||
|
|
||||||
this.$v.$touch()
|
this.$v.$touch()
|
||||||
|
|
||||||
if (!this.$v.$invalid) {
|
if (!this.$v.$invalid) {
|
||||||
this.signUp(this.user)
|
try {
|
||||||
|
await this.signUp(this.user)
|
||||||
|
this.$router.push('/main/friends')
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Registration failed: " + error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,11 @@
|
||||||
<input :disabled="isPending" v-model.trim='$v.user.username.$model' class='form-control' id='sign-up-username' placeholder='e.g. lain'>
|
<input :disabled="isPending" v-model.trim='$v.user.username.$model' class='form-control' id='sign-up-username' placeholder='e.g. lain'>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-error" v-if="$v.user.username.$dirty">
|
<div class="form-error" v-if="$v.user.username.$dirty">
|
||||||
<span class="error-required" v-if="!$v.user.username.required">Username is required.</span>
|
<ul>
|
||||||
|
<li v-if="!$v.user.username.required">
|
||||||
|
<span>{{$t('registration.validations.username_required')}}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='form-group'>
|
<div class='form-group'>
|
||||||
|
@ -25,7 +29,14 @@
|
||||||
<input :disabled="isPending" v-model='$v.user.email.$model' class='form-control' id='email' type="email">
|
<input :disabled="isPending" v-model='$v.user.email.$model' class='form-control' id='email' type="email">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-error" v-if="$v.user.email.$dirty">
|
<div class="form-error" v-if="$v.user.email.$dirty">
|
||||||
<span class="error-required" v-if="!$v.user.email.required">Email is required.</span>
|
<ul>
|
||||||
|
<li v-if="!$v.user.email.required">
|
||||||
|
<span>{{$t('registration.validations.email_required')}}</span>
|
||||||
|
</li>
|
||||||
|
<li v-if="!$v.user.email.email">
|
||||||
|
<span>{{$t('registration.validations.email_valid')}}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='form-group'>
|
<div class='form-group'>
|
||||||
|
@ -38,7 +49,11 @@
|
||||||
<input :disabled="isPending" v-model='user.password' class='form-control' id='sign-up-password' type='password'>
|
<input :disabled="isPending" v-model='user.password' class='form-control' id='sign-up-password' type='password'>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-error" v-if="$v.user.password.$dirty">
|
<div class="form-error" v-if="$v.user.password.$dirty">
|
||||||
<span class="error-required" v-if="!$v.user.password.required">Password is required.</span>
|
<ul>
|
||||||
|
<li v-if="!$v.user.password.required">
|
||||||
|
<span>{{$t('registration.validations.password_required')}}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class='form-group' :class="{ 'form-group--error': $v.user.confirm.$error }">
|
<div class='form-group' :class="{ 'form-group--error': $v.user.confirm.$error }">
|
||||||
|
@ -46,7 +61,14 @@
|
||||||
<input :disabled="isPending" v-model='user.confirm' class='form-control' id='sign-up-password-confirmation' type='password'>
|
<input :disabled="isPending" v-model='user.confirm' class='form-control' id='sign-up-password-confirmation' type='password'>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-error" v-if="$v.user.confirm.$dirty">
|
<div class="form-error" v-if="$v.user.confirm.$dirty">
|
||||||
<span class="error-required" v-if="!$v.user.confirm.required">Password confirmation is required.</span>
|
<ul>
|
||||||
|
<li v-if="!$v.user.confirm.required">
|
||||||
|
<span>{{$t('registration.validations.password_confirmation_required')}}</span>
|
||||||
|
</li>
|
||||||
|
<li v-if="!$v.user.confirm.sameAsPassword">
|
||||||
|
<span>{{$t('registration.validations.password_confirmation_match')}}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
<div class='form-group'>
|
<div class='form-group'>
|
||||||
|
@ -132,6 +154,17 @@
|
||||||
span {
|
span {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-error ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0 0 0 5px;
|
||||||
|
margin-top: 0;
|
||||||
|
|
||||||
|
li::before {
|
||||||
|
content: "• ";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form textarea {
|
form textarea {
|
||||||
|
|
|
@ -72,7 +72,15 @@
|
||||||
"fullname": "Display name",
|
"fullname": "Display name",
|
||||||
"password_confirm": "Password confirmation",
|
"password_confirm": "Password confirmation",
|
||||||
"registration": "Registration",
|
"registration": "Registration",
|
||||||
"token": "Invite token"
|
"token": "Invite token",
|
||||||
|
"validations": {
|
||||||
|
"username_required": "username should not be blank",
|
||||||
|
"email_required": "should not be blank",
|
||||||
|
"email_valid": "should be valid email",
|
||||||
|
"password_required": "should not be blank",
|
||||||
|
"password_confirmation_required": "should not be blank",
|
||||||
|
"password_confirmation_match": "should be the same as password"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"attachmentRadius": "Attachments",
|
"attachmentRadius": "Attachments",
|
||||||
|
|
|
@ -55,7 +55,15 @@
|
||||||
"fullname": "Отображаемое имя",
|
"fullname": "Отображаемое имя",
|
||||||
"password_confirm": "Подтверждение пароля",
|
"password_confirm": "Подтверждение пароля",
|
||||||
"registration": "Регистрация",
|
"registration": "Регистрация",
|
||||||
"token": "Код приглашения"
|
"token": "Код приглашения",
|
||||||
|
"validations": {
|
||||||
|
"username_required": "не должно быть пустым",
|
||||||
|
"email_required": "не должен быть пустым",
|
||||||
|
"email_valid": "должен быть корректный email адрес",
|
||||||
|
"password_required": "не должен быть пустым",
|
||||||
|
"password_confirmation_required": "не должно быть пустым",
|
||||||
|
"password_confirmation_match": "должно совпадать с паролем"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"attachmentRadius": "Прикреплённые файлы",
|
"attachmentRadius": "Прикреплённые файлы",
|
||||||
|
|
|
@ -52,13 +52,14 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
[SIGN_UP.PENDING] (state) {
|
[SIGN_UP.PENDING] (state) {
|
||||||
state[SIGN_UP.isPending] = true
|
state[SIGN_UP.isPending] = true
|
||||||
|
state[SIGN_UP.errors] = []
|
||||||
},
|
},
|
||||||
[SIGN_UP.SUCCESS] (state) {
|
[SIGN_UP.SUCCESS] (state) {
|
||||||
state[SIGN_UP.isPending] = false
|
state[SIGN_UP.isPending] = false
|
||||||
},
|
},
|
||||||
[SIGN_UP.FAILURE] (state, errors) {
|
[SIGN_UP.FAILURE] (state, errors) {
|
||||||
state[SIGN_UP.isPending] = false
|
state[SIGN_UP.isPending] = false
|
||||||
state[SIGN_UP.errors] = [...state[SIGN_UP.errors], ...errors]
|
state[SIGN_UP.errors] = errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,27 +98,29 @@ const users = {
|
||||||
async signUp (store, userInfo) {
|
async signUp (store, userInfo) {
|
||||||
store.commit(SIGN_UP.PENDING)
|
store.commit(SIGN_UP.PENDING)
|
||||||
|
|
||||||
let response = await store.rootState.api.backendInteractor.register(userInfo)
|
let rootState = store.rootState
|
||||||
|
|
||||||
|
let response = await rootState.api.backendInteractor.register(userInfo)
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = {
|
const data = {
|
||||||
oauth: store.state.oauth,
|
oauth: rootState.oauth,
|
||||||
instance: store.state.instance.server
|
instance: rootState.instance.server
|
||||||
}
|
}
|
||||||
let app = await oauthApi.getOrCreateApp(data)
|
let app = await oauthApi.getOrCreateApp(data)
|
||||||
let result = await oauthApi.getTokenWithCredentials({
|
let result = await oauthApi.getTokenWithCredentials({
|
||||||
app,
|
app,
|
||||||
instance: data.instance,
|
instance: data.instance,
|
||||||
username: this.user.username,
|
username: userInfo.username,
|
||||||
password: this.user.password
|
password: userInfo.password
|
||||||
})
|
})
|
||||||
store.commit(SIGN_UP.SUCCESS)
|
store.commit(SIGN_UP.SUCCESS)
|
||||||
store.commit('setToken', result.access_token)
|
store.commit('setToken', result.access_token)
|
||||||
store.dispatch('loginUser', result.access_token)
|
store.dispatch('loginUser', result.access_token)
|
||||||
this.$router.push('/main/friends')
|
|
||||||
} else {
|
} else {
|
||||||
let data = await response.json()
|
let data = await response.json()
|
||||||
let errors = humanizeErrors(JSON.parse(data.error))
|
let errors = humanizeErrors(JSON.parse(data.error))
|
||||||
store.commit(SIGN_UP.FAILURE, errors)
|
store.commit(SIGN_UP.FAILURE, errors)
|
||||||
|
throw Error(errors)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
logout (store) {
|
logout (store) {
|
||||||
|
|
Loading…
Reference in a new issue