diff options
| author | Henry Jameson <me@hjkos.com> | 2018-12-11 01:01:16 +0300 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2018-12-11 01:01:16 +0300 |
| commit | 3452864260d8a53afc839fb1265946ebfbd80cee (patch) | |
| tree | 73354d7eb98c73ef2330cb63b73dc127802bd1e4 /src/components | |
| parent | aeecd2b09b7c31644a2c601fc1b8d123e2b263b0 (diff) | |
| parent | fb5261b926adfb5b9bbe1bf55e36fe8b5f4eb57f (diff) | |
Merge remote-tracking branch 'upstream/develop' into feature/theming2
* upstream/develop:
Fix color fallback order
Use console.warn instead of console.log
Get rid of mutation_types file, use inline approach. Minor fixes
Add fallback color rule.
Change english validation error messages
Clean up the code
Validate name presence on client-side as well
Better styling for client-side validation. Add I18n for validation errors.
Fix broken ToS link. Fix linter errors
Add client validation for registration form
Use Array.reduce instead of lodash.reduce
Humanize validation errors returned on registration
Added user option to hide instance-specific panel, rearranged config screen to better categorize it / adjustments to language selector
fix
Diffstat (limited to 'src/components')
7 files changed, 183 insertions, 73 deletions
diff --git a/src/components/instance_specific_panel/instance_specific_panel.js b/src/components/instance_specific_panel/instance_specific_panel.js index 09e3d055..9bb5e945 100644 --- a/src/components/instance_specific_panel/instance_specific_panel.js +++ b/src/components/instance_specific_panel/instance_specific_panel.js @@ -2,6 +2,9 @@ const InstanceSpecificPanel = { computed: { instanceSpecificPanelContent () { return this.$store.state.instance.instanceSpecificPanelContent + }, + show () { + return !this.$store.state.config.hideISP } } } diff --git a/src/components/instance_specific_panel/instance_specific_panel.vue b/src/components/instance_specific_panel/instance_specific_panel.vue index ca8e00c0..a7b74667 100644 --- a/src/components/instance_specific_panel/instance_specific_panel.vue +++ b/src/components/instance_specific_panel/instance_specific_panel.vue @@ -1,5 +1,5 @@ <template> - <div class="instance-specific-panel"> + <div v-if="show" class="instance-specific-panel"> <div class="panel panel-default"> <div class="panel-body"> <div v-html="instanceSpecificPanelContent"> diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue index 4b541888..3f58af2c 100644 --- a/src/components/interface_language_switcher/interface_language_switcher.vue +++ b/src/components/interface_language_switcher/interface_language_switcher.vue @@ -1,5 +1,8 @@ <template> <div> + <label for="interface-language-switcher"> + {{ $t('settings.interfaceLanguage') }} + </label> <label for="interface-language-switcher" class='select'> <select id="interface-language-switcher" v-model="language"> <option v-for="(langCode, i) in languageCodes" :value="langCode"> diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js index f7f8a720..e5ead8bc 100644 --- a/src/components/registration/registration.js +++ b/src/components/registration/registration.js @@ -1,57 +1,61 @@ -import oauthApi from '../../services/new_api/oauth.js' +import { validationMixin } from 'vuelidate' +import { required, sameAs } from 'vuelidate/lib/validators' +import { mapActions, mapState } from 'vuex' const registration = { + mixins: [validationMixin], data: () => ({ - user: {}, - error: false, - registering: false + user: { + email: '', + fullname: '', + username: '', + password: '', + confirm: '' + } }), + validations: { + user: { + email: { required }, + username: { required }, + fullname: { required }, + password: { required }, + confirm: { + required, + sameAsPassword: sameAs('password') + } + } + }, 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') } - // Seems like this doesn't work at first page open for some reason - if (this.$store.state.instance.registrationOpen && this.token) { - this.$router.push('/registration') - } }, computed: { - termsofservice () { return this.$store.state.instance.tos }, - token () { return this.$route.params.token } + token () { return this.$route.params.token }, + ...mapState({ + registrationOpen: (state) => state.instance.registrationOpen, + signedIn: (state) => !!state.users.currentUser, + isPending: (state) => state.users.signUpPending, + serverValidationErrors: (state) => state.users.signUpErrors, + termsOfService: (state) => state.instance.tos + }) }, methods: { - submit () { - this.registering = true + ...mapActions(['signUp']), + async submit () { this.user.nickname = this.user.username this.user.token = this.token - this.$store.state.api.backendInteractor.register(this.user).then( - (response) => { - if (response.ok) { - const data = { - oauth: this.$store.state.oauth, - instance: this.$store.state.instance.server - } - oauthApi.getOrCreateApp(data).then((app) => { - oauthApi.getTokenWithCredentials( - { - app, - instance: data.instance, - username: this.user.username, - password: this.user.password}) - .then((result) => { - this.$store.commit('setToken', result.access_token) - this.$store.dispatch('loginUser', result.access_token) - this.$router.push('/main/friends') - }) - }) - } else { - this.registering = false - response.json().then((data) => { - this.error = data.error - }) - } + + this.$v.$touch() + + if (!this.$v.$invalid) { + try { + await this.signUp(this.user) + this.$router.push('/main/friends') + } catch (error) { + console.warn('Registration failed: ' + error) } - ) + } } } } diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue index 087cab6b..8cb1392b 100644 --- a/src/components/registration/registration.vue +++ b/src/components/registration/registration.vue @@ -7,50 +7,90 @@ <form v-on:submit.prevent='submit(user)' class='registration-form'> <div class='container'> <div class='text-fields'> - <div class='form-group'> - <label for='username'>{{$t('login.username')}}</label> - <input :disabled="registering" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'> + <div class='form-group' :class="{ 'form-group--error': $v.user.username.$error }"> + <label class='form--label' for='sign-up-username'>{{$t('login.username')}}</label> + <input :disabled="isPending" v-model.trim='$v.user.username.$model' class='form-control' id='sign-up-username' placeholder='e.g. lain'> </div> - <div class='form-group'> - <label for='fullname'>{{$t('registration.fullname')}}</label> - <input :disabled="registering" v-model='user.fullname' class='form-control' id='fullname' placeholder='e.g. Lain Iwakura'> + <div class="form-error" v-if="$v.user.username.$dirty"> + <ul> + <li v-if="!$v.user.username.required"> + <span>{{$t('registration.validations.username_required')}}</span> + </li> + </ul> </div> - <div class='form-group'> - <label for='email'>{{$t('registration.email')}}</label> - <input :disabled="registering" v-model='user.email' class='form-control' id='email' type="email"> + + <div class='form-group' :class="{ 'form-group--error': $v.user.fullname.$error }"> + <label class='form--label' for='sign-up-fullname'>{{$t('registration.fullname')}}</label> + <input :disabled="isPending" v-model.trim='$v.user.fullname.$model' class='form-control' id='sign-up-fullname' placeholder='e.g. Lain Iwakura'> </div> - <div class='form-group'> - <label for='bio'>{{$t('registration.bio')}}</label> - <input :disabled="registering" v-model='user.bio' class='form-control' id='bio'> + <div class="form-error" v-if="$v.user.fullname.$dirty"> + <ul> + <li v-if="!$v.user.fullname.required"> + <span>{{$t('registration.validations.fullname_required')}}</span> + </li> + </ul> </div> - <div class='form-group'> - <label for='password'>{{$t('login.password')}}</label> - <input :disabled="registering" v-model='user.password' class='form-control' id='password' type='password'> + + <div class='form-group' :class="{ 'form-group--error': $v.user.email.$error }"> + <label class='form--label' for='email'>{{$t('registration.email')}}</label> + <input :disabled="isPending" v-model='$v.user.email.$model' class='form-control' id='email' type="email"> </div> - <div class='form-group'> - <label for='password_confirmation'>{{$t('registration.password_confirm')}}</label> - <input :disabled="registering" v-model='user.confirm' class='form-control' id='password_confirmation' type='password'> + <div class="form-error" v-if="$v.user.email.$dirty"> + <ul> + <li v-if="!$v.user.email.required"> + <span>{{$t('registration.validations.email_required')}}</span> + </li> + </ul> </div> - <!-- + <div class='form-group'> - <label for='captcha'>Captcha</label> - <img src='/qvittersimplesecurity/captcha.jpg' alt='captcha' class='captcha'> - <input :disabled="registering" v-model='user.captcha' placeholder='Enter captcha' type='test' class='form-control' id='captcha'> + <label class='form--label' for='bio'>{{$t('registration.bio')}}</label> + <input :disabled="isPending" v-model='user.bio' class='form-control' id='bio'> + </div> + + <div class='form-group' :class="{ 'form-group--error': $v.user.password.$error }"> + <label class='form--label' for='sign-up-password'>{{$t('login.password')}}</label> + <input :disabled="isPending" v-model='user.password' class='form-control' id='sign-up-password' type='password'> + </div> + <div class="form-error" v-if="$v.user.password.$dirty"> + <ul> + <li v-if="!$v.user.password.required"> + <span>{{$t('registration.validations.password_required')}}</span> + </li> + </ul> + </div> + + <div class='form-group' :class="{ 'form-group--error': $v.user.confirm.$error }"> + <label class='form--label' for='sign-up-password-confirmation'>{{$t('registration.password_confirm')}}</label> + <input :disabled="isPending" v-model='user.confirm' class='form-control' id='sign-up-password-confirmation' type='password'> + </div> + <div class="form-error" v-if="$v.user.confirm.$dirty"> + <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 class='form-group' v-if='token' > <label for='token'>{{$t('registration.token')}}</label> <input disabled='true' v-model='token' class='form-control' id='token' type='text'> </div> <div class='form-group'> - <button :disabled="registering" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button> + <button :disabled="isPending" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button> </div> </div> - <div class='terms-of-service' v-html="termsofservice"> + + <div class='terms-of-service' v-html="termsOfService"> </div> </div> - <div v-if="error" class='form-group'> - <div class='alert error'>{{error}}</div> + <div v-if="serverValidationErrors.length" class='form-group'> + <div class='alert error'> + <span v-for="error in serverValidationErrors">{{error}}</span> + </div> </div> </form> </div> @@ -60,6 +100,7 @@ <script src="./registration.js"></script> <style lang="scss"> @import '../../_variables.scss'; +$validations-cRed: #f04124; .registration-form { display: flex; @@ -89,6 +130,55 @@ flex-direction: column; padding: 0.3em 0.0em 0.3em; line-height:24px; + margin-bottom: 1em; + } + + @keyframes shakeError { + 0% { + transform: translateX(0); } + 15% { + transform: translateX(0.375rem); } + 30% { + transform: translateX(-0.375rem); } + 45% { + transform: translateX(0.375rem); } + 60% { + transform: translateX(-0.375rem); } + 75% { + transform: translateX(0.375rem); } + 90% { + transform: translateX(-0.375rem); } + 100% { + transform: translateX(0); } } + + .form-group--error { + animation-name: shakeError; + animation-duration: .6s; + animation-timing-function: ease-in-out; + } + + .form-group--error .form--label { + color: $validations-cRed; + color: var(--cRed, $validations-cRed); + } + + .form-error { + margin-top: -0.7em; + text-align: left; + + span { + font-size: 12px; + } + } + + .form-error ul { + list-style: none; + padding: 0 0 0 5px; + margin-top: 0; + + li::before { + content: "• "; + } } form textarea { @@ -102,8 +192,6 @@ } .btn { - //align-self: flex-start; - //width: 10em; margin-top: 0.6em; height: 28px; } diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index 91a2014a..19bd2e5b 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -13,6 +13,7 @@ const settings = { hideAttachmentsLocal: user.hideAttachments, hideAttachmentsInConvLocal: user.hideAttachmentsInConv, hideNsfwLocal: user.hideNsfw, + hideISPLocal: user.hideISP, hidePostStatsLocal: typeof user.hidePostStats === 'undefined' ? instance.hidePostStats : user.hidePostStats, @@ -83,6 +84,9 @@ const settings = { hideNsfwLocal (value) { this.$store.dispatch('setOption', { name: 'hideNsfw', value }) }, + hideISPLocal (value) { + this.$store.dispatch('setOption', { name: 'hideISP', value }) + }, 'notificationVisibilityLocal.likes' (value) { this.$store.dispatch('setOption', { name: 'notificationVisibility', value: this.$store.state.config.notificationVisibility }) }, diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 64b8f231..dec33505 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -14,7 +14,7 @@ <div @click.prevent class="alert transparent" v-if="!currentSaveStateNotice.error"> {{ $t('settings.saving_ok') }} </div> - </template> + </template> </transition> </div> <div class="panel-body"> @@ -22,8 +22,16 @@ <tab-switcher> <div :label="$t('settings.general')" > <div class="setting-item"> - <h2>{{ $t('settings.interfaceLanguage') }}</h2> - <interface-language-switcher /> + <h2>{{ $t('settings.interface') }}</h2> + <ul class="setting-list"> + <li> + <interface-language-switcher /> + </li> + <li> + <input type="checkbox" id="hideISP" v-model="hideISPLocal"> + <label for="hideISP">{{$t('settings.hide_isp')}}</label> + </li> + </ul> </div> <div class="setting-item"> <h2>{{$t('nav.timeline')}}</h2> |
