Register.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <template>
  2. <div class="modal is-active">
  3. <div
  4. class="modal-background"
  5. @click="
  6. closeModal({
  7. sector: 'header',
  8. modal: 'register'
  9. })
  10. "
  11. />
  12. <div class="modal-card">
  13. <header class="modal-card-head">
  14. <p class="modal-card-title">Register</p>
  15. <button
  16. class="delete"
  17. @click="
  18. closeModal({
  19. sector: 'header',
  20. modal: 'register'
  21. })
  22. "
  23. />
  24. </header>
  25. <section class="modal-card-body">
  26. <p class="control">
  27. <label class="label">Email</label>
  28. <input
  29. v-model="email.value"
  30. class="input"
  31. type="email"
  32. placeholder="Email..."
  33. @blur="onInputBlur('email')"
  34. autofocus
  35. />
  36. </p>
  37. <transition name="fadein-helpbox">
  38. <input-help-box
  39. v-if="email.entered"
  40. :valid="email.valid"
  41. :message="email.message"
  42. ></input-help-box>
  43. </transition>
  44. <p class="control">
  45. <label class="label">Username</label>
  46. <input
  47. v-model="username.value"
  48. class="input"
  49. type="text"
  50. placeholder="Username..."
  51. @blur="onInputBlur('username')"
  52. />
  53. </p>
  54. <transition name="fadein-helpbox">
  55. <input-help-box
  56. v-if="username.entered"
  57. :valid="username.valid"
  58. :message="username.message"
  59. ></input-help-box>
  60. </transition>
  61. <p class="control">
  62. <label class="label">Password</label>
  63. <input
  64. v-model="password.value"
  65. class="input"
  66. type="password"
  67. placeholder="Password..."
  68. @blur="onInputBlur('password')"
  69. @keypress="$parent.submitOnEnter(submitModal, $event)"
  70. />
  71. </p>
  72. <transition name="fadein-helpbox">
  73. <input-help-box
  74. v-if="password.entered"
  75. :valid="password.valid"
  76. :message="password.message"
  77. ></input-help-box>
  78. </transition>
  79. <br />
  80. <p>
  81. By logging in/registering you agree to our
  82. <router-link to="/terms"> Terms of Service </router-link
  83. >&nbsp;and
  84. <router-link to="/privacy"> Privacy Policy </router-link>.
  85. </p>
  86. </section>
  87. <footer class="modal-card-foot">
  88. <a class="button is-primary" href="#" @click="submitModal()"
  89. >Submit</a
  90. >
  91. <a
  92. class="button is-github"
  93. :href="serverDomain + '/auth/github/authorize'"
  94. @click="githubRedirect()"
  95. >
  96. <div class="icon">
  97. <img class="invert" src="/assets/social/github.svg" />
  98. </div>
  99. &nbsp;&nbsp;Register with GitHub
  100. </a>
  101. </footer>
  102. </div>
  103. </div>
  104. </template>
  105. <script>
  106. import { mapActions } from "vuex";
  107. import Toast from "toasters";
  108. import InputHelpBox from "../ui/InputHelpBox.vue";
  109. import validation from "../../validation";
  110. export default {
  111. components: { InputHelpBox },
  112. data() {
  113. return {
  114. username: {
  115. value: "",
  116. valid: false,
  117. entered: false,
  118. message: "Please enter a valid username."
  119. },
  120. email: {
  121. value: "",
  122. valid: false,
  123. entered: false,
  124. message: "Please enter a valid email address."
  125. },
  126. password: {
  127. value: "",
  128. valid: false,
  129. entered: false,
  130. message: "Please enter a valid password."
  131. },
  132. recaptcha: {
  133. key: "",
  134. token: "",
  135. enabled: false
  136. },
  137. serverDomain: ""
  138. };
  139. },
  140. watch: {
  141. // eslint-disable-next-line
  142. "username.value": function(value) {
  143. if (!validation.isLength(value, 2, 32)) {
  144. this.username.message =
  145. "Username must have between 2 and 32 characters.";
  146. this.username.valid = false;
  147. } else if (!validation.regex.azAZ09_.test(value)) {
  148. this.username.message =
  149. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.";
  150. this.username.valid = false;
  151. } else {
  152. this.username.message = "Everything looks great!";
  153. this.username.valid = true;
  154. }
  155. },
  156. // eslint-disable-next-line
  157. "email.value": function(value) {
  158. if (!validation.isLength(value, 3, 254)) {
  159. this.email.message =
  160. "Email must have between 3 and 254 characters.";
  161. this.email.valid = false;
  162. } else if (
  163. value.indexOf("@") !== value.lastIndexOf("@") ||
  164. !validation.regex.emailSimple.test(value)
  165. ) {
  166. this.email.message = "Invalid Email format.";
  167. this.email.valid = false;
  168. } else {
  169. this.email.message = "Everything looks great!";
  170. this.email.valid = true;
  171. }
  172. },
  173. // eslint-disable-next-line
  174. "password.value": function(value) {
  175. if (!validation.isLength(value, 6, 200)) {
  176. this.password.message =
  177. "Password must have between 6 and 200 characters.";
  178. this.password.valid = false;
  179. } else if (!validation.regex.password.test(value)) {
  180. this.password.message =
  181. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.";
  182. this.password.valid = false;
  183. } else {
  184. this.password.message = "Everything looks great!";
  185. this.password.valid = true;
  186. }
  187. }
  188. },
  189. mounted() {
  190. lofig.get("serverDomain").then(serverDomain => {
  191. this.serverDomain = serverDomain;
  192. });
  193. lofig.get("recaptcha").then(obj => {
  194. this.recaptcha.enabled = obj.enabled;
  195. if (obj.enabled === true) {
  196. this.recaptcha.key = obj.key;
  197. const recaptchaScript = document.createElement("script");
  198. recaptchaScript.onload = () => {
  199. grecaptcha.ready(() => {
  200. grecaptcha
  201. .execute(this.recaptcha.key, { action: "login" })
  202. .then(token => {
  203. this.recaptcha.token = token;
  204. });
  205. });
  206. };
  207. recaptchaScript.setAttribute(
  208. "src",
  209. `https://www.google.com/recaptcha/api.js?render=${this.recaptcha.key}`
  210. );
  211. document.head.appendChild(recaptchaScript);
  212. }
  213. });
  214. },
  215. methods: {
  216. submitModal() {
  217. if (
  218. !this.username.valid ||
  219. !this.email.valid ||
  220. !this.password.valid
  221. )
  222. return new Toast({
  223. content: "Please ensure all fields are valid.",
  224. timeout: 5000
  225. });
  226. return this.register({
  227. username: this.username.value,
  228. email: this.email.value,
  229. password: this.password.value,
  230. recaptchaToken: this.recaptcha.token
  231. })
  232. .then(res => {
  233. if (res.status === "success") window.location.href = "/";
  234. })
  235. .catch(
  236. err => new Toast({ content: err.message, timeout: 5000 })
  237. );
  238. },
  239. onInputBlur(inputName) {
  240. this[inputName].entered = true;
  241. },
  242. githubRedirect() {
  243. localStorage.setItem("github_redirect", this.$route.path);
  244. },
  245. ...mapActions("modalVisibility", ["closeModal"]),
  246. ...mapActions("user/auth", ["register"])
  247. }
  248. };
  249. </script>
  250. <style lang="scss" scoped>
  251. @import "../../styles/global.scss";
  252. .night-mode {
  253. .modal-card,
  254. .modal-card-head,
  255. .modal-card-body,
  256. .modal-card-foot {
  257. background-color: $night-mode-bg-secondary;
  258. }
  259. .label,
  260. p:not(.help) {
  261. color: $night-mode-text;
  262. }
  263. }
  264. .button.is-github {
  265. background-color: $dark-grey-2;
  266. color: $white !important;
  267. }
  268. .is-github:focus {
  269. background-color: $dark-grey-3;
  270. }
  271. .is-primary:focus {
  272. background-color: #028bca !important;
  273. }
  274. .invert {
  275. filter: brightness(5);
  276. }
  277. #recaptcha {
  278. padding: 10px 0;
  279. }
  280. a {
  281. color: $primary-color;
  282. }
  283. </style>
  284. <style lang="scss">
  285. @import "../../styles/global.scss";
  286. .grecaptcha-badge {
  287. z-index: 2000;
  288. }
  289. </style>