diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/login_form/login_form.vue | 19 | ||||
| -rw-r--r-- | src/components/post_status_form/post_status_form.vue | 12 | ||||
| -rw-r--r-- | src/components/registration/registration.js | 29 | ||||
| -rw-r--r-- | src/components/registration/registration.vue | 136 | ||||
| -rw-r--r-- | src/components/settings/settings.js | 36 | ||||
| -rw-r--r-- | src/components/settings/settings.vue | 43 | ||||
| -rw-r--r-- | src/main.js | 4 | ||||
| -rw-r--r-- | src/modules/users.js | 2 | ||||
| -rw-r--r-- | src/services/api/api.service.js | 57 | ||||
| -rw-r--r-- | src/services/backend_interactor_service/backend_interactor_service.js | 4 |
10 files changed, 336 insertions, 6 deletions
diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue index b2fa5341..585af6f6 100644 --- a/src/components/login_form/login_form.vue +++ b/src/components/login_form/login_form.vue @@ -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'}" 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> diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index a95f92ab..a17d6479 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -80,6 +80,18 @@ } } + + .btn { + cursor: pointer; + } + + .btn[disabled] { + cursor: not-allowed; + } + + .icon-cancel { + cursor: pointer; + } form { display: flex; flex-direction: column; diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js new file mode 100644 index 00000000..93be9baa --- /dev/null +++ b/src/components/registration/registration.js @@ -0,0 +1,29 @@ +const registration = { + data: () => ({ + user: {}, + error: false, + registering: false + }), + 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 diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue new file mode 100644 index 00000000..f010d8ab --- /dev/null +++ b/src/components/registration/registration.vue @@ -0,0 +1,136 @@ +<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'> + <h4>Terms of Service</h4> + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> + </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> diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index 998aa354..b8aa876b 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -7,6 +7,8 @@ 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'), + previewfile: null, autoLoadLocal: this.$store.state.config.autoLoad, hoverPreviewLocal: this.$store.state.config.hoverPreview, muteWordsString: this.$store.state.config.muteWords.join('\n') @@ -15,6 +17,40 @@ const settings = { 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 + /*this.$store.state.api.backendInteractor.updateAvatar({params: {img}}).then((user) => { + if (!user.error) { + this.$store.commit('addNewUsers', [user]) + this.$store.commit('setCurrentUser', user) + } + })*/ + } + reader.readAsDataURL(file) + }, + submitAvatar () { + if (!this.previewfile) + return + const img = this.previewfile + this.$store.state.api.backendInteractor.updateAvatar({params: {img}}).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 }) diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index af0242c4..f2442194 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -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"> + </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,37 @@ width: 100%; height: 100px; } + + .old-avatar { + width: 128px; + border-radius: 5px; + } + + .new-avatar { + max-width: 100%; + border-radius: 5px; + } + + .btn { + margin-top: 1em; + min-height: 28px; + width: 10em; + } + + .cropper { + //position: absolute; + cursor: move; + width: 128px; + height: 128px; + border:1px solid #fff; + background-color: #000000; + .sub { + width: 100%; + height: 100%; + margin: -1px -1px -1px -1px ; + border:1px dashed #000; + } + } } .setting-list { list-style-type: none; diff --git a/src/main.js b/src/main.js index e5ecf228..dd59dea7 100644 --- a/src/main.js +++ b/src/main.js @@ -9,6 +9,7 @@ import ConversationPage from './components/conversation-page/conversation-page.v import Mentions from './components/mentions/mentions.vue' import UserProfile from './components/user_profile/user_profile.vue' import Settings from './components/settings/settings.vue' +import Registration from './components/registration/registration.vue' import statusesModule from './modules/statuses.js' import usersModule from './modules/users.js' @@ -60,7 +61,8 @@ const routes = [ { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'user-profile', path: '/users/:id', component: UserProfile }, { name: 'mentions', path: '/:username/mentions', component: Mentions }, - { name: 'settings', path: '/settings', component: Settings } + { name: 'settings', path: '/settings', component: Settings }, + { name: 'registration', path: '/registration', component: Registration } ] const router = new VueRouter({ diff --git a/src/modules/users.js b/src/modules/users.js index 22e0133c..b68f67e6 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -24,7 +24,7 @@ export const mutations = { set(user, 'muted', muted) }, setCurrentUser (state, user) { - state.currentUser = user + state.currentUser = merge(state.currentUser || {}, user) }, beginLogin (state) { state.loggingIn = true diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 59e3a1c3..e848d076 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -17,13 +17,15 @@ const FRIENDS_URL = '/api/statuses/friends.json' const FOLLOWING_URL = '/api/friendships/create.json' const UNFOLLOWING_URL = '/api/friendships/destroy.json' const QVITTER_USER_PREF_URL = '/api/qvitter/set_profile_pref.json' +const REGISTRATION_URL = '/api/account/register.json' +const AVATAR_UPDATE_URL = '/api/qvitter/update_avatar.json' const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json' const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json' // const USER_URL = '/api/users/show.json' -const oldfetch = window.fetch +import { each, map } from 'lodash' -import { map } from 'lodash' +const oldfetch = window.fetch let fetch = (url, options) => { const baseUrl = '' @@ -31,6 +33,55 @@ let fetch = (url, options) => { return oldfetch(fullUrl, options) } +// Params +// cropH +// cropW +// cropX +// cropY +// img (base 64 encodend data url) +const updateAvatar = ({credentials, params}) => { + let url = AVATAR_UPDATE_URL + + const form = new FormData() + + each(params, (value, key) => { + if (value) { + form.append(key, value) + } + }) + return fetch(url, { + headers: authHeaders(credentials), + method: 'POST', + body: form + }).then((data) => data.json()) +} + +// Params needed: +// nickname +// email +// fullname +// password +// password_confirm +// +// Optional +// bio +// homepage +// location +const register = (params) => { + const form = new FormData() + + each(params, (value, key) => { + if (value) { + form.append(key, value) + } + }) + + return fetch(REGISTRATION_URL, { + method: 'POST', + body: form + }) +} + const authHeaders = (user) => { if (user && user.username && user.password) { return { 'Authorization': `Basic ${btoa(`${user.username}:${user.password}`)}` } @@ -220,6 +271,8 @@ const apiService = { fetchAllFollowing, setUserMute, fetchMutes, + register, + updateAvatar, externalProfile } diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index f2d01c70..5dbbf4b3 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -36,6 +36,8 @@ const backendInteractorService = (credentials) => { const fetchMutes = () => apiService.fetchMutes({credentials}) + const register = (params) => apiService.register(params) + const updateAvatar = ({params}) => apiService.updateAvatar({credentials, params}) const externalProfile = (profileUrl) => apiService.externalProfile(profileUrl) const backendInteractorServiceInstance = { @@ -49,6 +51,8 @@ const backendInteractorService = (credentials) => { startFetching, setUserMute, fetchMutes, + register, + updateAvatar, externalProfile } |
