From 5b95994cacff214032284c9e6d7f9bc3b7f64d7f Mon Sep 17 00:00:00 2001 From: Bram Wiepjes <bramw@protonmail.com> Date: Mon, 10 Jun 2019 16:58:28 +0200 Subject: [PATCH] created vue login and register pages with validation only --- .editorconfig | 2 +- web-frontend/.eslintrc.js | 1 + web-frontend/layouts/login.vue | 10 ++ web-frontend/nuxt.config.js | 12 +- web-frontend/package.json | 3 +- web-frontend/pages/login/index.vue | 91 +++++++++++++ web-frontend/pages/login/signup.vue | 129 +++++++++++++++++++ web-frontend/plugins/Vuelidate.js | 4 + web-frontend/test/pages/index.spec.js | 2 +- web-frontend/test/pages/login/index.spec.js | 9 ++ web-frontend/test/pages/login/signup.spec.js | 9 ++ web-frontend/yarn.lock | 14 +- 12 files changed, 267 insertions(+), 19 deletions(-) create mode 100644 web-frontend/layouts/login.vue create mode 100644 web-frontend/pages/login/index.vue create mode 100644 web-frontend/pages/login/signup.vue create mode 100644 web-frontend/plugins/Vuelidate.js create mode 100644 web-frontend/test/pages/login/index.spec.js create mode 100644 web-frontend/test/pages/login/signup.spec.js diff --git a/.editorconfig b/.editorconfig index 7a3d0e60d..5bd2bab6d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,7 +11,7 @@ insert_final_newline = true [Makefile] indent_style = tab -[*.{js,yml,scss,json,eslintrc,stylelintrc,vue}] +[*.{js,yml,scss,json,eslintrc,stylelintrc,vue,html}] indent_size = 2 [*.md] diff --git a/web-frontend/.eslintrc.js b/web-frontend/.eslintrc.js index df2633137..17e51b0de 100644 --- a/web-frontend/.eslintrc.js +++ b/web-frontend/.eslintrc.js @@ -19,5 +19,6 @@ module.exports = { ], // add your custom rules here rules: { + 'no-console': 0 } } diff --git a/web-frontend/layouts/login.vue b/web-frontend/layouts/login.vue new file mode 100644 index 000000000..26a13a8d9 --- /dev/null +++ b/web-frontend/layouts/login.vue @@ -0,0 +1,10 @@ +<template> + <div> + <div class="box-page-header"></div> + <div class="box-page"> + <div class="box login-page login-page-login"> + <nuxt /> + </div> + </div> + </div> +</template> diff --git a/web-frontend/nuxt.config.js b/web-frontend/nuxt.config.js index 65051437a..d152bcad1 100644 --- a/web-frontend/nuxt.config.js +++ b/web-frontend/nuxt.config.js @@ -1,7 +1,5 @@ import StyleLintPlugin from 'stylelint-webpack-plugin' -import pkg from './package' - export default { mode: 'universal', @@ -9,13 +7,11 @@ export default { ** Headers of the page */ head: { - title: pkg.name, + title: 'Baserow', meta: [ { charset: 'utf-8' }, - { name: 'viewport', content: 'width=device-width, initial-scale=1' }, - { hid: 'description', name: 'description', content: pkg.description } - ], - link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] + { name: 'viewport', content: 'width=device-width, initial-scale=1' } + ] }, /* @@ -31,7 +27,7 @@ export default { /* ** Plugins to load before mounting the App */ - plugins: [], + plugins: [{ src: '@/plugins/Vuelidate.js' }], /* ** Nuxt.js modules diff --git a/web-frontend/package.json b/web-frontend/package.json index eb832cb88..424f49619 100644 --- a/web-frontend/package.json +++ b/web-frontend/package.json @@ -18,7 +18,8 @@ "@nuxtjs/axios": "^5.3.6", "cross-env": "^5.2.0", "normalize-scss": "^7.0.1", - "nuxt": "^2.4.0" + "nuxt": "^2.4.0", + "vuelidate": "^0.7.4" }, "devDependencies": { "@nuxtjs/eslint-config": "^0.0.1", diff --git a/web-frontend/pages/login/index.vue b/web-frontend/pages/login/index.vue new file mode 100644 index 000000000..db3c47e46 --- /dev/null +++ b/web-frontend/pages/login/index.vue @@ -0,0 +1,91 @@ +<template> + <div> + <h1 class="box-title"> + <img src="@/static/img/logo.svg" alt="" /> + </h1> + <form @submit.prevent="login"> + <div class="control"> + <label class="control-label">E-mail address</label> + <div class="control-elements"> + <input + v-model="credentials.email" + :class="{ 'input-error': $v.credentials.email.$error }" + type="text" + class="input input-large" + @blur="$v.credentials.email.$touch()" + /> + <div v-if="$v.credentials.email.$error" class="error"> + Please enter a valid e-mail address. + </div> + </div> + </div> + <div class="control"> + <label class="control-label">Password</label> + <div class="control-elements"> + <input + v-model="credentials.password" + :class="{ 'input-error': $v.credentials.password.$error }" + type="password" + class="input input-large" + @blur="$v.credentials.password.$touch()" + /> + <div v-if="$v.credentials.password.$error" class="error"> + A password is required. + </div> + </div> + </div> + <div class="actions"> + <ul class="action-links"> + <li> + <nuxt-link :to="{ name: 'login-signup' }"> + Sign up + </nuxt-link> + </li> + </ul> + <button + :class="{ 'button-loading': loading }" + class="button button-large" + > + Sign in + <i class="fas fa-lock-open"></i> + </button> + </div> + </form> + </div> +</template> + +<script> +import { required, email } from 'vuelidate/lib/validators' + +export default { + layout: 'login', + head() { + return { + title: 'Login' + } + }, + data() { + return { + loading: false, + credentials: { + email: '', + password: '' + } + } + }, + validations: { + credentials: { + email: { required, email }, + password: { required } + } + }, + methods: { + login() { + this.$v.$touch() + if (!this.$v.$invalid) { + this.loading = true + } + } + } +} +</script> diff --git a/web-frontend/pages/login/signup.vue b/web-frontend/pages/login/signup.vue new file mode 100644 index 000000000..80fbe7d86 --- /dev/null +++ b/web-frontend/pages/login/signup.vue @@ -0,0 +1,129 @@ +<template> + <div> + <h1 class="box-title">Sign up</h1> + <form @submit.prevent="register"> + <div class="control"> + <label class="control-label">E-mail address</label> + <div class="control-elements"> + <input + v-model="account.email" + :class="{ 'input-error': $v.account.email.$error }" + type="text" + class="input input-large" + @blur="$v.account.email.$touch()" + /> + <div v-if="$v.account.email.$error" class="error"> + Please enter a valid e-mail address. + </div> + </div> + </div> + <div class="control"> + <label class="control-label">Your name</label> + <div class="control-elements"> + <input + v-model="account.name" + :class="{ 'input-error': $v.account.name.$error }" + type="text" + class="input input-large" + @blur="$v.account.name.$touch()" + /> + <div v-if="$v.account.name.$error" class="error"> + A minimum of two characters is required here. + </div> + </div> + </div> + <div class="control"> + <label class="control-label">Password</label> + <div class="control-elements"> + <input + v-model="account.password" + :class="{ 'input-error': $v.account.password.$error }" + type="password" + class="input input-large" + @blur="$v.account.password.$touch()" + /> + <div v-if="$v.account.password.$error" class="error"> + A password is required. + </div> + </div> + </div> + <div class="control"> + <label class="control-label">Repeat password</label> + <div class="control-elements"> + <input + v-model="account.passwordConfirm" + :class="{ 'input-error': $v.account.passwordConfirm.$error }" + type="password" + class="input input-large" + @blur="$v.account.passwordConfirm.$touch()" + /> + <div v-if="$v.account.passwordConfirm.$error" class="error"> + This field must match your password field. + </div> + </div> + </div> + <div class="actions"> + <ul class="action-links"> + <li> + <nuxt-link :to="{ name: 'login' }"> + <i class="fas fa-arrow-left"></i> + Back + </nuxt-link> + </li> + </ul> + <button + :class="{ 'button-loading': loading }" + class="button button-large" + > + Sign up + <i class="fas fa-user-plus"></i> + </button> + </div> + </form> + </div> +</template> + +<script> +import { required, email, sameAs, minLength } from 'vuelidate/lib/validators' + +export default { + layout: 'login', + head() { + return { + title: 'Create new account' + } + }, + validations: { + account: { + email: { required, email }, + name: { + required, + minLength: minLength(2) + }, + password: { required }, + passwordConfirm: { + sameAsPassword: sameAs('password') + } + } + }, + data() { + return { + loading: false, + account: { + email: '', + name: '', + password: '', + passwordConfirm: '' + } + } + }, + methods: { + register() { + this.$v.$touch() + if (!this.$v.$invalid) { + this.loading = true + } + } + } +} +</script> diff --git a/web-frontend/plugins/Vuelidate.js b/web-frontend/plugins/Vuelidate.js new file mode 100644 index 000000000..bfbc65e98 --- /dev/null +++ b/web-frontend/plugins/Vuelidate.js @@ -0,0 +1,4 @@ +import Vue from 'vue' +import Vuelidate from 'vuelidate' + +Vue.use(Vuelidate) diff --git a/web-frontend/test/pages/index.spec.js b/web-frontend/test/pages/index.spec.js index faad5805d..1b11c57cb 100644 --- a/web-frontend/test/pages/index.spec.js +++ b/web-frontend/test/pages/index.spec.js @@ -1,7 +1,7 @@ import { mount } from '@vue/test-utils' import Index from '@/pages/index.vue' -describe('Logo', () => { +describe('Home', () => { test('is a Vue instance', () => { const wrapper = mount(Index) expect(wrapper.isVueInstance()).toBeTruthy() diff --git a/web-frontend/test/pages/login/index.spec.js b/web-frontend/test/pages/login/index.spec.js new file mode 100644 index 000000000..dd258ff8e --- /dev/null +++ b/web-frontend/test/pages/login/index.spec.js @@ -0,0 +1,9 @@ +import { mount } from '@vue/test-utils' +import Index from '@/pages/login/index.vue' + +describe('Login', () => { + test('is a Vue instance', () => { + const wrapper = mount(Index) + expect(wrapper.isVueInstance()).toBeTruthy() + }) +}) diff --git a/web-frontend/test/pages/login/signup.spec.js b/web-frontend/test/pages/login/signup.spec.js new file mode 100644 index 000000000..3d21708d8 --- /dev/null +++ b/web-frontend/test/pages/login/signup.spec.js @@ -0,0 +1,9 @@ +import { mount } from '@vue/test-utils' +import Signup from '@/pages/login/signup.vue' + +describe('Signup', () => { + test('is a Vue instance', () => { + const wrapper = mount(Signup) + expect(wrapper.isVueInstance()).toBeTruthy() + }) +}) diff --git a/web-frontend/yarn.lock b/web-frontend/yarn.lock index 74b8b40fe..bca539b6f 100644 --- a/web-frontend/yarn.lock +++ b/web-frontend/yarn.lock @@ -4933,7 +4933,7 @@ html-webpack-plugin@^3.2.0: toposort "^1.0.0" util.promisify "1.0.0" -htmlparser2@^3.10.0, htmlparser2@^3.3.0, htmlparser2@^3.9.1: +htmlparser2@^3.10.0, htmlparser2@^3.3.0: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -9724,13 +9724,6 @@ stylelint-config-standard@^18.2.0: dependencies: stylelint-config-recommended "^2.2.0" -stylelint-processor-html@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stylelint-processor-html/-/stylelint-processor-html-1.0.0.tgz#6892b6b2855a45f0291cd845191d6908130a2918" - integrity sha1-aJK2soVaRfApHNhFGR1pCBMKKRg= - dependencies: - htmlparser2 "^3.9.1" - stylelint-webpack-plugin@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/stylelint-webpack-plugin/-/stylelint-webpack-plugin-0.10.5.tgz#0b6e0d373ff5e03baa8197ebe0f2625981bd266b" @@ -10640,6 +10633,11 @@ vue@^2.6.10: resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== +vuelidate@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.4.tgz#5a0e54be09ac0192f1aa3387d74b92e0945bf8aa" + integrity sha512-QHZWYOL325Zo+2K7VBNEJTZ496Kd8Z31p85aQJFldKudUUGBmgw4zu4ghl4CyqPwjRCmqZ9lDdx4FSdMnu4fGg== + vuex@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e"