register.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <template lang="pug">
  2. v-app
  3. .register
  4. v-container(grid-list-lg)
  5. v-layout(row, wrap)
  6. v-flex(
  7. xs12
  8. offset-sm1, sm10
  9. offset-md2, md8
  10. offset-lg3, lg6
  11. offset-xl4, xl4
  12. )
  13. transition(name='zoom')
  14. v-card.elevation-5.md2(v-show='isShown')
  15. v-toolbar(color='indigo', flat, dense, dark)
  16. v-spacer
  17. .subheading {{ $t('auth:registerTitle') }}
  18. v-spacer
  19. v-card-text.text-xs-center
  20. h1.display-1.indigo--text.py-2 {{ siteTitle }}
  21. .body-2 {{ $t('auth:registerSubTitle') }}
  22. v-text-field.md2.mt-3(
  23. solo
  24. flat
  25. prepend-icon='email'
  26. background-color='grey lighten-4'
  27. hide-details
  28. ref='iptEmail'
  29. v-model='email'
  30. :placeholder='$t("auth:fields.email")'
  31. color='indigo'
  32. )
  33. v-text-field.md2.mt-2(
  34. solo
  35. flat
  36. prepend-icon='vpn_key'
  37. background-color='grey lighten-4'
  38. ref='iptPassword'
  39. v-model='password'
  40. :append-icon='hidePassword ? "visibility" : "visibility_off"'
  41. @click:append='() => (hidePassword = !hidePassword)'
  42. :type='hidePassword ? "password" : "text"'
  43. :placeholder='$t("auth:fields.password")'
  44. color='indigo'
  45. loading
  46. )
  47. password-strength(slot='progress', v-model='password')
  48. v-text-field.md2.mt-2(
  49. solo
  50. flat
  51. prepend-icon='vpn_key'
  52. background-color='grey lighten-4'
  53. hide-details
  54. ref='iptVerifyPassword'
  55. v-model='verifyPassword'
  56. @click:append='() => (hidePassword = !hidePassword)'
  57. type='password'
  58. :placeholder='$t("auth:fields.verifyPassword")'
  59. color='indigo'
  60. )
  61. v-text-field.md2.mt-2(
  62. solo
  63. flat
  64. prepend-icon='person'
  65. background-color='grey lighten-4'
  66. hide-details
  67. ref='iptName'
  68. v-model='name'
  69. :placeholder='$t("auth:fields.name")'
  70. @keyup.enter='register'
  71. color='indigo'
  72. )
  73. v-card-actions.pb-4
  74. v-spacer
  75. v-btn.md2(
  76. block
  77. large
  78. dark
  79. color='indigo'
  80. @click='register'
  81. round
  82. :loading='isLoading'
  83. ) {{ $t('auth:actions.register') }}
  84. v-spacer
  85. v-divider
  86. v-card-actions.py-3.grey.lighten-4
  87. v-spacer
  88. i18next.caption(path='auth:switchToLogin.text', tag='div')
  89. a.caption(href='/login', place='link') {{ $t('auth:switchToLogin.link') }}
  90. v-spacer
  91. loader(v-model='isLoading', :color='loaderColor', :title='loaderTitle', :subtitle='$t(`auth:pleaseWait`)')
  92. nav-footer(color='grey darken-4', dark-color='grey darken-4')
  93. </template>
  94. <script>
  95. /* global siteConfig */
  96. import _ from 'lodash'
  97. import Cookies from 'js-cookie'
  98. import validate from 'validate.js'
  99. import PasswordStrength from './common/password-strength.vue'
  100. import registerMutation from 'gql/register/register-mutation-create.gql'
  101. export default {
  102. i18nOptions: { namespaces: 'auth' },
  103. components: {
  104. PasswordStrength
  105. },
  106. data () {
  107. return {
  108. email: '',
  109. password: '',
  110. verifyPassword: '',
  111. name: '',
  112. hidePassword: true,
  113. isLoading: false,
  114. isShown: false
  115. }
  116. },
  117. computed: {
  118. siteTitle () {
  119. return siteConfig.title
  120. }
  121. },
  122. mounted () {
  123. this.isShown = true
  124. this.$nextTick(() => {
  125. this.$refs.iptEmail.focus()
  126. })
  127. },
  128. methods: {
  129. /**
  130. * REGISTER
  131. */
  132. async register () {
  133. const validation = validate({
  134. email: this.email,
  135. password: this.password,
  136. verifyPassword: this.verifyPassword,
  137. name: this.name
  138. }, {
  139. email: {
  140. presence: {
  141. message: this.$t('auth:missingEmail'),
  142. allowEmpty: false
  143. },
  144. email: {
  145. message: this.$t('auth:invalidEmail')
  146. }
  147. },
  148. password: {
  149. presence: {
  150. message: this.$t('auth:missingPassword'),
  151. allowEmpty: false
  152. },
  153. length: {
  154. minimum: 6,
  155. tooShort: this.$t('auth:passwordTooShort')
  156. }
  157. },
  158. verifyPassword: {
  159. equality: {
  160. attribute: 'password',
  161. message: this.$t('auth:passwordNotMatch')
  162. }
  163. },
  164. name: {
  165. presence: {
  166. message: this.$t('auth:missingName'),
  167. allowEmpty: false
  168. },
  169. length: {
  170. minimum: 2,
  171. maximum: 255,
  172. tooShort: this.$t('auth:nameTooShort'),
  173. tooLong: this.$t('auth:nameTooLong')
  174. }
  175. },
  176. }, { fullMessages: false })
  177. if (validation) {
  178. if(validation.email) {
  179. this.$store.commit('showNotification', {
  180. style: 'red',
  181. message: validation.email[0],
  182. icon: 'warning'
  183. })
  184. this.$refs.iptEmail.focus()
  185. } else if (validation.password) {
  186. this.$store.commit('showNotification', {
  187. style: 'red',
  188. message: validation.password[0],
  189. icon: 'warning'
  190. })
  191. this.$refs.iptPassword.focus()
  192. } else if (validation.verifyPassword) {
  193. this.$store.commit('showNotification', {
  194. style: 'red',
  195. message: validation.verifyPassword[0],
  196. icon: 'warning'
  197. })
  198. this.$refs.iptVerifyPassword.focus()
  199. } else {
  200. this.$store.commit('showNotification', {
  201. style: 'red',
  202. message: validation.name[0],
  203. icon: 'warning'
  204. })
  205. this.$refs.iptName.focus()
  206. }
  207. } else {
  208. this.isLoading = true
  209. try {
  210. let resp = await this.$apollo.mutate({
  211. mutation: registerMutation,
  212. variables: {
  213. email: this.email,
  214. password: this.password,
  215. name: this.name
  216. }
  217. })
  218. if (_.has(resp, 'data.authentication.register')) {
  219. let respObj = _.get(resp, 'data.authentication.register', {})
  220. if (respObj.responseResult.succeeded === true) {
  221. this.$store.commit('showNotification', {
  222. message: 'Account created successfully! Redirecting...',
  223. style: 'success',
  224. icon: 'check'
  225. })
  226. Cookies.set('jwt', respObj.jwt, { expires: 365 })
  227. _.delay(() => {
  228. window.location.replace('/')
  229. }, 1000)
  230. } else {
  231. throw new Error(respObj.responseResult.message)
  232. }
  233. } else {
  234. throw new Error('Registration is unavailable at this time.')
  235. }
  236. } catch (err) {
  237. console.error(err)
  238. this.$store.commit('showNotification', {
  239. style: 'red',
  240. message: err.message,
  241. icon: 'warning'
  242. })
  243. this.isLoading = false
  244. }
  245. }
  246. }
  247. }
  248. }
  249. </script>
  250. <style lang="scss">
  251. .register {
  252. background-color: mc('indigo', '900');
  253. background-image: url('../static/svg/motif-blocks.svg');
  254. background-repeat: repeat;
  255. background-size: 200px;
  256. width: 100%;
  257. height: 100%;
  258. animation: loginBgReveal 20s linear infinite;
  259. @include keyframes(loginBgReveal) {
  260. 0% {
  261. background-position-x: 0;
  262. }
  263. 100% {
  264. background-position-x: 800px;
  265. }
  266. }
  267. &::before {
  268. content: '';
  269. position: absolute;
  270. background-image: url('../static/svg/motif-overlay.svg');
  271. background-attachment: fixed;
  272. background-size: cover;
  273. opacity: .5;
  274. top: 0;
  275. left: 0;
  276. width: 100vw;
  277. height: 100vh;
  278. }
  279. > .container {
  280. height: 100%;
  281. align-items: center;
  282. display: flex;
  283. }
  284. h1 {
  285. font-family: 'Varela Round' !important;
  286. }
  287. .v-text-field.centered input {
  288. text-align: center;
  289. }
  290. }
  291. </style>