feat: register validation + create + admin improvements
This commit is contained in:
@@ -151,6 +151,18 @@
|
||||
multiple
|
||||
chips
|
||||
)
|
||||
template(v-if='strategy.key === `local`')
|
||||
v-divider.mt-3
|
||||
v-subheader.pl-0 Security
|
||||
.pr-3
|
||||
v-switch.ml-3(
|
||||
:disabled='true'
|
||||
v-model='strategy.recaptcha'
|
||||
label='Use reCAPTCHA by Google'
|
||||
color='primary'
|
||||
hint='Protects against spam robots and malicious registrations.'
|
||||
persistent-hint
|
||||
)
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@@ -51,7 +51,7 @@
|
||||
.subheading Sponsors
|
||||
v-spacer
|
||||
v-btn(outline, small, href='https://opencollective.com/wikijs/order/1273') Become a Sponsor
|
||||
v-list(two-line, dense)
|
||||
v-list(two-line)
|
||||
template(v-for='(sponsor, idx) in sponsors')
|
||||
v-list-tile(:key='sponsor.id')
|
||||
v-list-tile-avatar
|
||||
@@ -89,6 +89,58 @@
|
||||
v-btn(icon, :href='backer.website', target='_blank')
|
||||
v-icon(color='grey') public
|
||||
v-divider(v-if='idx < backers.length - 1')
|
||||
v-toolbar(color='primary', dense, dark)
|
||||
.subheading Special Thanks
|
||||
v-list(two-line)
|
||||
v-list-tile
|
||||
v-list-tile-avatar
|
||||
img(src='https://static.requarks.io/logo/algolia.svg', alt='Algolia')
|
||||
v-list-tile-content
|
||||
v-list-tile-title Algolia
|
||||
v-list-tile-sub-title Algolia is a powerful search-as-a-service solution, made easy to use with API clients, UI libraries, and pre-built integrations.
|
||||
v-list-tile-action
|
||||
v-btn(icon, href='https://www.algolia.com/', target='_blank')
|
||||
v-icon(color='grey') public
|
||||
v-divider
|
||||
v-list-tile
|
||||
v-list-tile-avatar
|
||||
img(src='https://static.requarks.io/logo/browserstack.svg', alt='Browserstack')
|
||||
v-list-tile-content
|
||||
v-list-tile-title BrowserStack
|
||||
v-list-tile-sub-title BrowserStack is a cloud web and mobile testing platform that enables developers to test their websites and mobile applications.
|
||||
v-list-tile-action
|
||||
v-btn(icon, href='https://www.browserstack.com/', target='_blank')
|
||||
v-icon(color='grey') public
|
||||
v-divider
|
||||
v-list-tile
|
||||
v-list-tile-avatar
|
||||
img(src='https://static.requarks.io/logo/cloudflare.svg', alt='Cloudflare')
|
||||
v-list-tile-content
|
||||
v-list-tile-title Cloudflare
|
||||
v-list-tile-sub-title Providing content delivery network services, DDoS mitigation, Internet security and distributed domain name server services.
|
||||
v-list-tile-action
|
||||
v-btn(icon, href='https://www.cloudflare.com/', target='_blank')
|
||||
v-icon(color='grey') public
|
||||
v-divider
|
||||
v-list-tile
|
||||
v-list-tile-avatar
|
||||
img(src='https://static.requarks.io/logo/digitalocean.svg', alt='DigitalOcean')
|
||||
v-list-tile-content
|
||||
v-list-tile-title DigitalOcean
|
||||
v-list-tile-sub-title Providing developers and businesses a reliable, easy-to-use cloud computing platform of virtual servers (Droplets), object storage (Spaces), and more.
|
||||
v-list-tile-action
|
||||
v-btn(icon, href='https://m.do.co/c/5f7445bfa4d0', target='_blank')
|
||||
v-icon(color='grey') public
|
||||
v-divider
|
||||
v-list-tile
|
||||
v-list-tile-avatar
|
||||
img(src='/svg/logo-icons8.svg', alt='Icons8')
|
||||
v-list-tile-content
|
||||
v-list-tile-title Icons8
|
||||
v-list-tile-sub-title All the Icons You Need. Guaranteed.
|
||||
v-list-tile-action
|
||||
v-btn(icon, href='https://icons8.com', target='_blank')
|
||||
v-icon(color='grey') public
|
||||
|
||||
</template>
|
||||
|
||||
|
@@ -47,7 +47,7 @@
|
||||
avatar
|
||||
:key='rdr.key'
|
||||
@click='selectRenderer(rdr.key)'
|
||||
:class='currentRenderer.key === rdr.key ? "blue lighten-5" : ""'
|
||||
:class='currentRenderer.key === rdr.key ? (darkMode ? `grey darken-4-l4` : `blue lighten-5`) : ``'
|
||||
)
|
||||
v-list-tile-avatar
|
||||
v-icon(:color='currentRenderer.key === rdr.key ? "primary" : "grey"') {{rdr.icon}}
|
||||
@@ -120,6 +120,7 @@
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { DepGraph } from 'dependency-graph'
|
||||
import { get } from 'vuex-pathify'
|
||||
|
||||
import { StatusIndicator } from 'vue-status-indicator'
|
||||
|
||||
@@ -136,6 +137,9 @@ export default {
|
||||
currentRenderer: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
darkMode: get('site/dark'),
|
||||
},
|
||||
watch: {
|
||||
renderers(newValue, oldValue) {
|
||||
_.delay(() => {
|
||||
|
@@ -37,7 +37,7 @@
|
||||
v-list-tile-content
|
||||
v-list-tile-title Email
|
||||
v-list-tile-sub-title {{ user.email }}
|
||||
v-list-tile-action
|
||||
v-list-tile-action(v-if='!user.isSystem')
|
||||
v-btn(icon, color='grey', flat)
|
||||
v-icon edit
|
||||
v-divider
|
||||
@@ -50,7 +50,7 @@
|
||||
v-list-tile-action
|
||||
v-btn(icon, color='grey', flat)
|
||||
v-icon edit
|
||||
v-card.mt-3
|
||||
v-card.mt-3(v-if='!user.isSystem')
|
||||
v-toolbar(color='primary', dense, dark, flat)
|
||||
v-icon.mr-2 lock_outline
|
||||
span Authentication
|
||||
|
51
client/components/common/loader.vue
Normal file
51
client/components/common/loader.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template lang='pug'>
|
||||
v-dialog(v-model='value', persistent, max-width='350')
|
||||
v-card.loader-dialog.radius-7(:color='color', dark)
|
||||
v-card-text.text-xs-center.py-4
|
||||
atom-spinner.is-inline(
|
||||
:animation-duration='1000'
|
||||
:size='60'
|
||||
color='#FFF'
|
||||
)
|
||||
.subheading {{ title }}
|
||||
.caption {{ subtitle }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { AtomSpinner } from 'epic-spinners'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AtomSpinner
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'blue darken-3'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Working...'
|
||||
},
|
||||
subtitle: {
|
||||
type: String,
|
||||
default: 'Please wait'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.loader-dialog {
|
||||
.atom-spinner.is-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
.caption {
|
||||
color: rgba(255,255,255,.7);
|
||||
}
|
||||
}
|
||||
</style>
|
79
client/components/common/password-strength.vue
Normal file
79
client/components/common/password-strength.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template lang="pug">
|
||||
.password-strength
|
||||
v-progress-linear(
|
||||
:color='passwordStrengthColor'
|
||||
v-model='passwordStrength'
|
||||
height='2'
|
||||
)
|
||||
.caption(v-if='!hideText', :class='passwordStrengthColor + "--text"') {{passwordStrengthText}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import zxcvbn from 'zxcvbn'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
hideText: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
passwordStrength: 0,
|
||||
passwordStrengthColor: 'grey',
|
||||
passwordStrengthText: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(newValue) {
|
||||
this.checkPasswordStrength(newValue)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkPasswordStrength: _.debounce(function (pwd) {
|
||||
if (!pwd || pwd.length < 1) {
|
||||
this.passwordStrength = 0
|
||||
this.passwordStrengthColor = 'grey'
|
||||
this.passwordStrengthText = ''
|
||||
return
|
||||
}
|
||||
const strength = zxcvbn(pwd)
|
||||
this.passwordStrength = _.round((strength.score + 1 ) / 5 * 100)
|
||||
if (this.passwordStrength <= 20) {
|
||||
this.passwordStrengthColor = 'red'
|
||||
this.passwordStrengthText = 'Very Weak'
|
||||
} else if (this.passwordStrength <= 40) {
|
||||
this.passwordStrengthColor = 'orange'
|
||||
this.passwordStrengthText = 'Weak'
|
||||
} else if (this.passwordStrength <= 60) {
|
||||
this.passwordStrengthColor = 'teal'
|
||||
this.passwordStrengthText = 'Average'
|
||||
} else if (this.passwordStrength <= 80) {
|
||||
this.passwordStrengthColor = 'green'
|
||||
this.passwordStrengthText = 'Strong'
|
||||
} else {
|
||||
this.passwordStrengthColor = 'green'
|
||||
this.passwordStrengthText = 'Very Strong'
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.password-strength > .caption {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: calc(100% + 5px);
|
||||
}
|
||||
|
||||
</style>
|
@@ -30,16 +30,6 @@
|
||||
v-content
|
||||
component(:is='currentEditor')
|
||||
editor-modal-properties(v-model='dialogProps')
|
||||
v-dialog(v-model='dialogProgress', persistent, max-width='350')
|
||||
v-card(color='blue darken-3', dark)
|
||||
v-card-text.text-xs-center.py-4
|
||||
atom-spinner.is-inline(
|
||||
:animation-duration='1000'
|
||||
:size='60'
|
||||
color='#FFF'
|
||||
)
|
||||
.subheading {{ $t('editor:save.processing') }}
|
||||
.caption.blue--text.text--lighten-3 {{ $t('editor:save.pleaseWait') }}
|
||||
v-dialog(v-model='dialogEditorSelector', persistent, max-width='700')
|
||||
v-card.radius-7(color='blue darken-3', dark)
|
||||
v-card-text.text-xs-center.py-4
|
||||
@@ -88,6 +78,7 @@
|
||||
.caption.grey--text.text--darken-1 Drag-n-drop
|
||||
.caption.blue--text.text--lighten-2 This cannot be changed once the page is created.
|
||||
|
||||
loader(v-model='dialogProgress', :title='$t(`editor:save.processing`)', :subtitle='$t(`editor:save.pleaseWait`)')
|
||||
v-snackbar(
|
||||
:color='notification.style'
|
||||
bottom,
|
||||
|
@@ -15,7 +15,7 @@
|
||||
v-toolbar(color='primary', flat, dense, dark)
|
||||
v-spacer
|
||||
.subheading(v-if='screen === "tfa"') {{ $t('auth:tfa.subtitle') }}
|
||||
.subheading(v-else-if='selectedStrategy.key !== "local"') Login using {{ selectedStrategy.title }}
|
||||
.subheading(v-else-if='selectedStrategy.key !== "local"') {{ $t('auth:loginUsingStrategy', { strategy: selectedStrategy.title }) }}
|
||||
.subheading(v-else) {{ $t('auth:loginRequired') }}
|
||||
v-spacer
|
||||
v-card-text.text-xs-center
|
||||
@@ -80,12 +80,12 @@
|
||||
v-spacer
|
||||
v-card-actions.pb-3(v-if='selectedStrategy.key === "local"')
|
||||
v-spacer
|
||||
a.caption(href='') Forgot your password?
|
||||
a.caption(href='') {{ $t('auth:forgotPasswordLink') }}
|
||||
v-spacer
|
||||
template(v-if='isSocialShown')
|
||||
v-divider
|
||||
v-card-text.grey.lighten-4.text-xs-center
|
||||
.pb-2.body-2.text-xs-center.grey--text.text--darken-2 or login using...
|
||||
.pb-2.body-2.text-xs-center.grey--text.text--darken-2 {{ $t('auth:orLoginUsingStrategy') }}
|
||||
v-tooltip(top, v-for='strategy in strategies', :key='strategy.key')
|
||||
.social-login-btn.mr-2(
|
||||
slot='activator'
|
||||
@@ -99,8 +99,11 @@
|
||||
v-divider
|
||||
v-card-actions.py-3(:class='isSocialShown ? "" : "grey lighten-4"')
|
||||
v-spacer
|
||||
.caption Don't have an account yet? #[a.caption(href='') Create an account]
|
||||
i18next.caption(path='auth:switchToRegister.text', tag='div')
|
||||
a.caption(href='/register', place='link') {{ $t('auth:switchToRegister.link') }}
|
||||
v-spacer
|
||||
|
||||
loader(v-model='isLoading', :color='loaderColor', :title='loaderTitle', :subtitle='$t(`auth:pleaseWait`)')
|
||||
nav-footer(color='grey darken-4')
|
||||
</template>
|
||||
|
||||
@@ -128,6 +131,8 @@ export default {
|
||||
securityCode: '',
|
||||
loginToken: '',
|
||||
isLoading: false,
|
||||
loaderColor: 'grey darken-4',
|
||||
loaderTitle: 'Working...',
|
||||
isShown: false
|
||||
}
|
||||
},
|
||||
@@ -173,18 +178,20 @@ export default {
|
||||
if (this.username.length < 2) {
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: 'Enter a valid email / username.',
|
||||
message: this.$t('auth:invalidEmailUsername'),
|
||||
icon: 'warning'
|
||||
})
|
||||
this.$refs.iptEmail.focus()
|
||||
} else if (this.password.length < 2) {
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: 'Enter a valid password.',
|
||||
message: this.$t('auth:invalidPassword'),
|
||||
icon: 'warning'
|
||||
})
|
||||
this.$refs.iptPassword.focus()
|
||||
} else {
|
||||
this.loaderColor = 'grey darken-4'
|
||||
this.loaderTitle = this.$t('auth:signingIn')
|
||||
this.isLoading = true
|
||||
try {
|
||||
let resp = await this.$apollo.mutate({
|
||||
@@ -205,23 +212,20 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.iptTFA.focus()
|
||||
})
|
||||
this.isLoading = false
|
||||
} else {
|
||||
this.$store.commit('showNotification', {
|
||||
message: 'Login Successful! Redirecting...',
|
||||
style: 'success',
|
||||
icon: 'check'
|
||||
})
|
||||
this.loaderColor = 'green darken-1'
|
||||
this.loaderTitle = this.$t('auth:loginSuccess')
|
||||
Cookies.set('jwt', respObj.jwt, { expires: 365 })
|
||||
_.delay(() => {
|
||||
window.location.replace('/') // TEMPORARY - USE RETURNURL
|
||||
}, 1000)
|
||||
}
|
||||
this.isLoading = false
|
||||
} else {
|
||||
throw new Error(respObj.responseResult.message)
|
||||
}
|
||||
} else {
|
||||
throw new Error('Authentication is unavailable.')
|
||||
throw new Error(this.$t('auth:genericError'))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
@@ -270,7 +274,7 @@ export default {
|
||||
throw new Error(respObj.responseResult.message)
|
||||
}
|
||||
} else {
|
||||
throw new Error('Authentication is unavailable.')
|
||||
throw new Error(this.$t('auth:genericError'))
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
@@ -289,7 +293,6 @@ export default {
|
||||
query: strategiesQuery,
|
||||
update: (data) => data.authentication.strategies,
|
||||
watchLoading (isLoading) {
|
||||
this.isLoading = isLoading
|
||||
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'login-strategies-refresh')
|
||||
}
|
||||
}
|
||||
|
303
client/components/register.vue
Normal file
303
client/components/register.vue
Normal file
@@ -0,0 +1,303 @@
|
||||
<template lang="pug">
|
||||
v-app
|
||||
.register
|
||||
v-container(grid-list-lg)
|
||||
v-layout(row, wrap)
|
||||
v-flex(
|
||||
xs12
|
||||
offset-sm1, sm10
|
||||
offset-md2, md8
|
||||
offset-lg3, lg6
|
||||
offset-xl4, xl4
|
||||
)
|
||||
transition(name='zoom')
|
||||
v-card.elevation-5.md2(v-show='isShown')
|
||||
v-toolbar(color='indigo', flat, dense, dark)
|
||||
v-spacer
|
||||
.subheading {{ $t('auth:registerTitle') }}
|
||||
v-spacer
|
||||
v-card-text.text-xs-center
|
||||
h1.display-1.indigo--text.py-2 {{ siteTitle }}
|
||||
.body-2 {{ $t('auth:registerSubTitle') }}
|
||||
v-text-field.md2.mt-3(
|
||||
solo
|
||||
flat
|
||||
prepend-icon='email'
|
||||
background-color='grey lighten-4'
|
||||
hide-details
|
||||
ref='iptEmail'
|
||||
v-model='email'
|
||||
:placeholder='$t("auth:fields.email")'
|
||||
color='indigo'
|
||||
)
|
||||
v-text-field.md2.mt-2(
|
||||
solo
|
||||
flat
|
||||
prepend-icon='vpn_key'
|
||||
background-color='grey lighten-4'
|
||||
ref='iptPassword'
|
||||
v-model='password'
|
||||
:append-icon='hidePassword ? "visibility" : "visibility_off"'
|
||||
@click:append='() => (hidePassword = !hidePassword)'
|
||||
:type='hidePassword ? "password" : "text"'
|
||||
:placeholder='$t("auth:fields.password")'
|
||||
color='indigo'
|
||||
loading
|
||||
)
|
||||
password-strength(slot='progress', v-model='password')
|
||||
v-text-field.md2.mt-2(
|
||||
solo
|
||||
flat
|
||||
prepend-icon='vpn_key'
|
||||
background-color='grey lighten-4'
|
||||
hide-details
|
||||
ref='iptVerifyPassword'
|
||||
v-model='verifyPassword'
|
||||
@click:append='() => (hidePassword = !hidePassword)'
|
||||
type='password'
|
||||
:placeholder='$t("auth:fields.verifyPassword")'
|
||||
color='indigo'
|
||||
)
|
||||
v-text-field.md2.mt-2(
|
||||
solo
|
||||
flat
|
||||
prepend-icon='person'
|
||||
background-color='grey lighten-4'
|
||||
hide-details
|
||||
ref='iptName'
|
||||
v-model='name'
|
||||
:placeholder='$t("auth:fields.name")'
|
||||
@keyup.enter='register'
|
||||
color='indigo'
|
||||
)
|
||||
v-card-actions.pb-4
|
||||
v-spacer
|
||||
v-btn.md2(
|
||||
block
|
||||
large
|
||||
dark
|
||||
color='indigo'
|
||||
@click='register'
|
||||
round
|
||||
:loading='isLoading'
|
||||
) {{ $t('auth:actions.register') }}
|
||||
v-spacer
|
||||
v-divider
|
||||
v-card-actions.py-3.grey.lighten-4
|
||||
v-spacer
|
||||
i18next.caption(path='auth:switchToLogin.text', tag='div')
|
||||
a.caption(href='/login', place='link') {{ $t('auth:switchToLogin.link') }}
|
||||
v-spacer
|
||||
|
||||
loader(v-model='isLoading', :color='loaderColor', :title='loaderTitle', :subtitle='$t(`auth:pleaseWait`)')
|
||||
nav-footer(color='grey darken-4', dark-color='grey darken-4')
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global siteConfig */
|
||||
|
||||
import _ from 'lodash'
|
||||
import Cookies from 'js-cookie'
|
||||
import validate from 'validate.js'
|
||||
import PasswordStrength from './common/password-strength.vue'
|
||||
|
||||
import registerMutation from 'gql/register/register-mutation-create.gql'
|
||||
|
||||
export default {
|
||||
i18nOptions: { namespaces: 'auth' },
|
||||
components: {
|
||||
PasswordStrength
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
verifyPassword: '',
|
||||
name: '',
|
||||
hidePassword: true,
|
||||
isLoading: false,
|
||||
isShown: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
siteTitle () {
|
||||
return siteConfig.title
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.isShown = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.iptEmail.focus()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* REGISTER
|
||||
*/
|
||||
async register () {
|
||||
const validation = validate({
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
verifyPassword: this.verifyPassword,
|
||||
name: this.name
|
||||
}, {
|
||||
email: {
|
||||
presence: {
|
||||
message: this.$t('auth:missingEmail'),
|
||||
allowEmpty: false
|
||||
},
|
||||
email: {
|
||||
message: this.$t('auth:invalidEmail')
|
||||
}
|
||||
},
|
||||
password: {
|
||||
presence: {
|
||||
message: this.$t('auth:missingPassword'),
|
||||
allowEmpty: false
|
||||
},
|
||||
length: {
|
||||
minimum: 6,
|
||||
tooShort: this.$t('auth:passwordTooShort')
|
||||
}
|
||||
},
|
||||
verifyPassword: {
|
||||
equality: {
|
||||
attribute: 'password',
|
||||
message: this.$t('auth:passwordNotMatch')
|
||||
}
|
||||
},
|
||||
name: {
|
||||
presence: {
|
||||
message: this.$t('auth:missingName'),
|
||||
allowEmpty: false
|
||||
},
|
||||
length: {
|
||||
minimum: 2,
|
||||
maximum: 255,
|
||||
tooShort: this.$t('auth:nameTooShort'),
|
||||
tooLong: this.$t('auth:nameTooLong')
|
||||
}
|
||||
},
|
||||
}, { fullMessages: false })
|
||||
|
||||
if (validation) {
|
||||
if(validation.email) {
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: validation.email[0],
|
||||
icon: 'warning'
|
||||
})
|
||||
this.$refs.iptEmail.focus()
|
||||
} else if (validation.password) {
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: validation.password[0],
|
||||
icon: 'warning'
|
||||
})
|
||||
this.$refs.iptPassword.focus()
|
||||
} else if (validation.verifyPassword) {
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: validation.verifyPassword[0],
|
||||
icon: 'warning'
|
||||
})
|
||||
this.$refs.iptVerifyPassword.focus()
|
||||
} else {
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: validation.name[0],
|
||||
icon: 'warning'
|
||||
})
|
||||
this.$refs.iptName.focus()
|
||||
}
|
||||
} else {
|
||||
this.isLoading = true
|
||||
try {
|
||||
let resp = await this.$apollo.mutate({
|
||||
mutation: registerMutation,
|
||||
variables: {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
name: this.name
|
||||
}
|
||||
})
|
||||
if (_.has(resp, 'data.authentication.register')) {
|
||||
let respObj = _.get(resp, 'data.authentication.register', {})
|
||||
if (respObj.responseResult.succeeded === true) {
|
||||
this.$store.commit('showNotification', {
|
||||
message: 'Account created successfully! Redirecting...',
|
||||
style: 'success',
|
||||
icon: 'check'
|
||||
})
|
||||
Cookies.set('jwt', respObj.jwt, { expires: 365 })
|
||||
_.delay(() => {
|
||||
window.location.replace('/')
|
||||
}, 1000)
|
||||
} else {
|
||||
throw new Error(respObj.responseResult.message)
|
||||
}
|
||||
} else {
|
||||
throw new Error('Registration is unavailable at this time.')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
this.$store.commit('showNotification', {
|
||||
style: 'red',
|
||||
message: err.message,
|
||||
icon: 'warning'
|
||||
})
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.register {
|
||||
background-color: mc('indigo', '900');
|
||||
background-image: url('../static/svg/motif-blocks.svg');
|
||||
background-repeat: repeat;
|
||||
background-size: 200px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: loginBgReveal 20s linear infinite;
|
||||
|
||||
@include keyframes(loginBgReveal) {
|
||||
0% {
|
||||
background-position-x: 0;
|
||||
}
|
||||
100% {
|
||||
background-position-x: 800px;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-image: url('../static/svg/motif-overlay.svg');
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
opacity: .5;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
> .container {
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Varela Round' !important;
|
||||
}
|
||||
|
||||
.v-text-field.centered input {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user