register.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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='fadeUp')
  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-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='mdi-email'
  26. :background-color='$vuetify.theme.dark ? `grey darken-3` : `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='mdi-form-textbox-password'
  37. :background-color='$vuetify.theme.dark ? `grey darken-3` : `grey lighten-4`'
  38. ref='iptPassword'
  39. v-model='password'
  40. :append-icon='hidePassword ? "mdi-eye-off" : "mdi-eye"'
  41. @click:append='() => (hidePassword = !hidePassword)'
  42. :type='hidePassword ? "password" : "text"'
  43. :placeholder='$t("auth:fields.password")'
  44. color='indigo'
  45. loading
  46. counter='255'
  47. )
  48. password-strength(slot='progress', v-model='password')
  49. v-text-field.md2.mt-2(
  50. solo
  51. flat
  52. prepend-icon='mdi-form-textbox-password'
  53. :background-color='$vuetify.theme.dark ? `grey darken-3` : `grey lighten-4`'
  54. hide-details
  55. ref='iptVerifyPassword'
  56. v-model='verifyPassword'
  57. @click:append='() => (hidePassword = !hidePassword)'
  58. type='password'
  59. :placeholder='$t("auth:fields.verifyPassword")'
  60. color='indigo'
  61. )
  62. v-text-field.md2.mt-2(
  63. solo
  64. flat
  65. prepend-icon='mdi-account'
  66. :background-color='$vuetify.theme.dark ? `grey darken-3` : `grey lighten-4`'
  67. ref='iptName'
  68. v-model='name'
  69. :placeholder='$t("auth:fields.name")'
  70. @keyup.enter='register'
  71. color='indigo'
  72. counter='255'
  73. )
  74. v-card-actions.pb-4
  75. v-spacer
  76. v-btn.md2(
  77. width='100%'
  78. max-width='250px'
  79. large
  80. dark
  81. color='indigo'
  82. @click='register'
  83. rounded
  84. :loading='isLoading'
  85. ) {{ $t('auth:actions.register') }}
  86. v-spacer
  87. v-divider
  88. v-card-actions.py-3.grey(:class='$vuetify.theme.dark ? `darken-4-l1` : `lighten-4`')
  89. v-spacer
  90. i18next.caption(path='auth:switchToLogin.text', tag='div')
  91. a.caption(href='/login', place='link') {{ $t('auth:switchToLogin.link') }}
  92. v-spacer
  93. loader(v-model='isLoading', :mode='loaderMode', :icon='loaderIcon', :color='loaderColor', :title='loaderTitle', :subtitle='loaderSubtitle')
  94. nav-footer(color='grey darken-5', dark-color='grey darken-5')
  95. notify(style='padding-top: 64px;')
  96. </template>
  97. <script>
  98. /* global siteConfig */
  99. import _ from 'lodash'
  100. import validate from 'validate.js'
  101. import PasswordStrength from './common/password-strength.vue'
  102. import registerMutation from 'gql/register/register-mutation-create.gql'
  103. export default {
  104. i18nOptions: { namespaces: 'auth' },
  105. components: {
  106. PasswordStrength
  107. },
  108. data () {
  109. return {
  110. email: '',
  111. password: '',
  112. verifyPassword: '',
  113. name: '',
  114. hidePassword: true,
  115. isLoading: false,
  116. isShown: false,
  117. loaderColor: 'grey darken-4',
  118. loaderTitle: 'Working...',
  119. loaderSubtitle: 'Please wait',
  120. loaderMode: 'icon',
  121. loaderIcon: 'checkmark'
  122. }
  123. },
  124. computed: {
  125. siteTitle () {
  126. return siteConfig.title
  127. }
  128. },
  129. mounted () {
  130. this.isShown = true
  131. this.$nextTick(() => {
  132. this.$refs.iptEmail.focus()
  133. })
  134. },
  135. methods: {
  136. /**
  137. * REGISTER
  138. */
  139. async register () {
  140. const validation = validate({
  141. email: this.email,
  142. password: this.password,
  143. verifyPassword: this.verifyPassword,
  144. name: this.name
  145. }, {
  146. email: {
  147. presence: {
  148. message: this.$t('auth:missingEmail'),
  149. allowEmpty: false
  150. },
  151. email: {
  152. message: this.$t('auth:invalidEmail')
  153. }
  154. },
  155. password: {
  156. presence: {
  157. message: this.$t('auth:missingPassword'),
  158. allowEmpty: false
  159. },
  160. length: {
  161. minimum: 6,
  162. tooShort: this.$t('auth:passwordTooShort')
  163. }
  164. },
  165. verifyPassword: {
  166. equality: {
  167. attribute: 'password',
  168. message: this.$t('auth:passwordNotMatch')
  169. }
  170. },
  171. name: {
  172. presence: {
  173. message: this.$t('auth:missingName'),
  174. allowEmpty: false
  175. },
  176. length: {
  177. minimum: 2,
  178. maximum: 255,
  179. tooShort: this.$t('auth:nameTooShort'),
  180. tooLong: this.$t('auth:nameTooLong')
  181. }
  182. }
  183. }, { fullMessages: false })
  184. if (validation) {
  185. if (validation.email) {
  186. this.$store.commit('showNotification', {
  187. style: 'red',
  188. message: validation.email[0],
  189. icon: 'warning'
  190. })
  191. this.$refs.iptEmail.focus()
  192. } else if (validation.password) {
  193. this.$store.commit('showNotification', {
  194. style: 'red',
  195. message: validation.password[0],
  196. icon: 'warning'
  197. })
  198. this.$refs.iptPassword.focus()
  199. } else if (validation.verifyPassword) {
  200. this.$store.commit('showNotification', {
  201. style: 'red',
  202. message: validation.verifyPassword[0],
  203. icon: 'warning'
  204. })
  205. this.$refs.iptVerifyPassword.focus()
  206. } else {
  207. this.$store.commit('showNotification', {
  208. style: 'red',
  209. message: validation.name[0],
  210. icon: 'warning'
  211. })
  212. this.$refs.iptName.focus()
  213. }
  214. } else {
  215. this.loaderColor = 'grey darken-4'
  216. this.loaderTitle = this.$t('auth:registering')
  217. this.loaderSubtitle = this.$t(`auth:pleaseWait`)
  218. this.loaderMode = 'loading'
  219. this.isLoading = true
  220. try {
  221. let resp = await this.$apollo.mutate({
  222. mutation: registerMutation,
  223. variables: {
  224. email: this.email,
  225. password: this.password,
  226. name: this.name
  227. }
  228. })
  229. if (_.has(resp, 'data.authentication.register')) {
  230. let respObj = _.get(resp, 'data.authentication.register', {})
  231. if (respObj.responseResult.succeeded === true) {
  232. this.loaderColor = 'grey darken-4'
  233. this.loaderTitle = this.$t('auth:registerSuccess')
  234. this.loaderSubtitle = this.$t(`auth:registerCheckEmail`)
  235. this.loaderMode = 'icon'
  236. this.isShown = false
  237. } else {
  238. throw new Error(respObj.responseResult.message)
  239. }
  240. } else {
  241. throw new Error(this.$t('auth:genericError'))
  242. }
  243. } catch (err) {
  244. console.error(err)
  245. this.$store.commit('showNotification', {
  246. style: 'red',
  247. message: err.message,
  248. icon: 'warning'
  249. })
  250. this.isLoading = false
  251. }
  252. }
  253. }
  254. }
  255. }
  256. </script>
  257. <style lang="scss">
  258. .register {
  259. background-color: mc('indigo', '900');
  260. background-image: url('../static/svg/motif-blocks.svg');
  261. background-repeat: repeat;
  262. background-size: 200px;
  263. width: 100%;
  264. height: 100%;
  265. animation: loginBgReveal 20s linear infinite;
  266. @include keyframes(loginBgReveal) {
  267. 0% {
  268. background-position-x: 0;
  269. }
  270. 100% {
  271. background-position-x: 800px;
  272. }
  273. }
  274. &::before {
  275. content: '';
  276. position: absolute;
  277. background-image: url('../static/svg/motif-overlay.svg');
  278. background-attachment: fixed;
  279. background-size: cover;
  280. opacity: .5;
  281. top: 0;
  282. left: 0;
  283. width: 100vw;
  284. height: 100vh;
  285. }
  286. > .container {
  287. height: 100%;
  288. align-items: center;
  289. display: flex;
  290. }
  291. .v-text-field.centered input {
  292. text-align: center;
  293. }
  294. }
  295. </style>