Merge branch 'feature/registration' into 'develop'

Add a registration form.

See merge request !76
This commit is contained in:
lambadalambda 2017-06-21 12:22:28 -04:00
commit 937705ccb0
13 changed files with 357 additions and 10 deletions

View file

@ -4,7 +4,8 @@ const LoginForm = {
authError: false
}),
computed: {
loggingIn () { return this.$store.state.users.loggingIn }
loggingIn () { return this.$store.state.users.loggingIn },
registrationOpen () { return this.$store.state.config.registrationOpen }
},
methods: {
submit () {

View file

@ -15,7 +15,10 @@
<input :disabled="loggingIn" v-model='user.password' class='form-control' id='password' type='password'>
</div>
<div class='form-group'>
<button :disabled="loggingIn" type='submit' class='btn btn-default base05 base01-background'>Submit</button>
<div class='login-bottom'>
<div><router-link :to="{name: 'registration'}" v-if='registrationOpen' class='register'>Register</router-link></div>
<button :disabled="loggingIn" type='submit' class='btn btn-default base05 base01-background'>Log in</button>
</div>
</div>
<div v-if="authError" class='form-group'>
<div class='error base05'>{{authError}}</div>
@ -39,8 +42,8 @@
}
.btn {
margin-top: 1.0em;
min-height: 28px;
width: 10em;
}
.error {
@ -50,6 +53,18 @@
min-height: 28px;
line-height: 28px;
}
.register {
flex: 1 1;
}
.login-bottom {
margin-top: 1.0em;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
}
</style>

View file

@ -80,6 +80,18 @@
}
}
.btn {
cursor: pointer;
}
.btn[disabled] {
cursor: not-allowed;
}
.icon-cancel {
cursor: pointer;
}
form {
display: flex;
flex-direction: column;

View file

@ -0,0 +1,37 @@
const registration = {
data: () => ({
user: {},
error: false,
registering: false
}),
created () {
if (!this.$store.state.config.registrationOpen || !!this.$store.state.users.currentUser) {
this.$router.push('/main/all')
}
},
computed: {
termsofservice () { return this.$store.state.config.tos }
},
methods: {
submit () {
this.registering = true
this.user.nickname = this.user.username
this.$store.state.api.backendInteractor.register(this.user).then(
(response) => {
if (response.ok) {
this.$store.dispatch('loginUser', this.user)
this.$router.push('/main/all')
this.registering = false
} else {
this.registering = false
response.json().then((data) => {
this.error = data.error
})
}
}
)
}
}
}
export default registration

View file

@ -0,0 +1,134 @@
<template>
<div class="settings panel panel-default base00-background">
<div class="panel-heading base01-background base04">
Registration
</div>
<div class="panel-body">
<form v-on:submit.prevent='submit(user)' class='registration-form'>
<div class='container'>
<div class='text-fields'>
<div class='form-group'>
<label for='username'>Username</label>
<input :disabled="registering" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'>
</div>
<div class='form-group'>
<label for='fullname'>Fullname</label>
<input :disabled="registering" v-model='user.fullname' class='form-control' id='fullname' placeholder='e.g. Lain Iwakura'>
</div>
<div class='form-group'>
<label for='email'>Email</label>
<input :disabled="registering" v-model='user.email' class='form-control' id='email' type="email">
</div>
<div class='form-group'>
<label for='bio'>Bio</label>
<input :disabled="registering" v-model='user.bio' class='form-control' id='bio'>
</div>
<div class='form-group'>
<label for='password'>Password</label>
<input :disabled="registering" v-model='user.password' class='form-control' id='password' type='password'>
</div>
<div class='form-group'>
<label for='password_confirmation'>Password confirmation</label>
<input :disabled="registering" v-model='user.confirm' class='form-control' id='password_confirmation' type='password'>
</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'>
</div>
-->
<div class='form-group'>
<button :disabled="registering" type='submit' class='btn btn-default base05 base01-background'>Submit</button>
</div>
</div>
<div class='terms-of-service' v-html="termsofservice">
</div>
</div>
<div v-if="error" class='form-group'>
<div class='error base05'>{{error}}</div>
</div>
</form>
</div>
</div>
</template>
<script src="./registration.js"></script>
<style lang="scss">
.registration-form {
display: flex;
flex-direction: column;
margin: 0.6em;
.container {
display: flex;
flex-direction: row;
//margin-bottom: 1em;
}
.terms-of-service {
flex: 0 1 50%;
margin: 0.8em;
}
.text-fields {
margin-top: 0.6em;
flex: 1 0;
display: flex;
flex-direction: column;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0.0em 0.3em;
line-height:24px;
}
form textarea {
border: solid;
border-width: 1px;
border-color: silver;
border-radius: 5px;
line-height:16px;
padding: 5px;
resize: vertical;
}
input {
border-width: 1px;
border-style: solid;
border-color: silver;
border-radius: 5px;
padding: 0.1em 0.2em 0.2em 0.2em;
}
.captcha {
max-width: 350px;
margin-bottom: 0.4em;
}
.btn {
//align-self: flex-start;
//width: 10em;
margin-top: 0.6em;
height: 28px;
}
.error {
border-radius: 5px;
text-align: center;
margin: 0.5em 0.6em 0;
background-color: rgba(255, 48, 16, 0.65);
min-height: 28px;
line-height: 28px;
}
}
@media all and (max-width: 959px) {
.registration-form .container {
flex-direction: column-reverse;
}
}
</style>

View file

@ -7,14 +7,58 @@ const settings = {
hideAttachmentsLocal: this.$store.state.config.hideAttachments,
hideAttachmentsInConvLocal: this.$store.state.config.hideAttachmentsInConv,
hideNsfwLocal: this.$store.state.config.hideNsfw,
muteWordsString: this.$store.state.config.muteWords.join('\n'),
autoLoadLocal: this.$store.state.config.autoLoad,
hoverPreviewLocal: this.$store.state.config.hoverPreview,
muteWordsString: this.$store.state.config.muteWords.join('\n')
previewfile: null
}
},
components: {
StyleSwitcher
},
computed: {
user () {
return this.$store.state.users.currentUser
}
},
methods: {
uploadAvatar ({target}) {
const file = target.files[0]
// eslint-disable-next-line no-undef
const reader = new FileReader()
reader.onload = ({target}) => {
const img = target.result
this.previewfile = img
}
reader.readAsDataURL(file)
},
submitAvatar () {
if (!this.previewfile) { return }
const img = this.previewfile
// eslint-disable-next-line no-undef
let imginfo = new Image()
let cropX, cropY, cropW, cropH
imginfo.src = this.previewfile
if (imginfo.height > imginfo.width) {
cropX = 0
cropW = imginfo.width
cropY = Math.floor((imginfo.height - imginfo.width) / 2)
cropH = imginfo.width
} else {
cropY = 0
cropH = imginfo.height
cropX = Math.floor((imginfo.width - imginfo.height) / 2)
cropW = imginfo.height
}
this.$store.state.api.backendInteractor.updateAvatar({params: {img, cropX, cropY, cropW, cropH}}).then((user) => {
if (!user.error) {
this.$store.commit('addNewUsers', [user])
this.$store.commit('setCurrentUser', user)
}
})
}
},
watch: {
hideAttachmentsLocal (value) {
this.$store.dispatch('setOption', { name: 'hideAttachments', value })

View file

@ -8,6 +8,18 @@
<h2>Theme</h2>
<style-switcher></style-switcher>
</div>
<div class="setting-item" v-if="user">
<h2>Avatar</h2>
<p>Your current avatar:</p>
<img :src="user.profile_image_url_original" class="old-avatar"></img>
<p>Set new avatar:</p>
<img class="new-avatar" v-bind:src="previewfile" v-if="previewfile">
</img>
<div>
<input name="avatar-upload" id="avatar-upload" type="file" @change="uploadAvatar" ></input>
</div>
<button class="btn btn-default base05 base01-background" v-if="previewfile" @click="submitAvatar">Submit</button>
</div>
<div class="setting-item">
<h2>Filtering</h2>
<p>All notices containing these words will be muted, one per line</p>
@ -52,6 +64,24 @@
width: 100%;
height: 100px;
}
.old-avatar {
width: 128px;
border-radius: 5px;
}
.new-avatar {
object-fit: cover;
width: 128px;
height: 128px;
border-radius: 5px;
}
.btn {
margin-top: 1em;
min-height: 28px;
width: 10em;
}
}
.setting-list {
list-style-type: none;