Login.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, ref } from "vue";
  3. import { useRoute } from "vue-router";
  4. import Toast from "toasters";
  5. import { storeToRefs } from "pinia";
  6. import { useConfigStore } from "@/stores/config";
  7. import { useUserAuthStore } from "@/stores/userAuth";
  8. import { useModalsStore } from "@/stores/modals";
  9. const Modal = defineAsyncComponent(() => import("@/components/Modal.vue"));
  10. const route = useRoute();
  11. const email = ref("");
  12. const password = ref({
  13. value: "",
  14. visible: false
  15. });
  16. const passwordElement = ref();
  17. const configStore = useConfigStore();
  18. const { githubAuthentication, oidcAuthentication, registrationDisabled } =
  19. storeToRefs(configStore);
  20. const { login } = useUserAuthStore();
  21. const { openModal, closeCurrentModal } = useModalsStore();
  22. const submitModal = () => {
  23. if (!email.value || !password.value.value) return;
  24. login({
  25. email: email.value,
  26. password: password.value.value
  27. })
  28. .then((res: any) => {
  29. if (res.status === "success") window.location.reload();
  30. })
  31. .catch(err => new Toast(err.message));
  32. };
  33. const checkForAutofill = (type, event) => {
  34. if (
  35. event.target.value !== "" &&
  36. event.inputType === undefined &&
  37. event.data === undefined &&
  38. event.dataTransfer === undefined &&
  39. event.isComposing === undefined
  40. )
  41. submitModal();
  42. };
  43. const togglePasswordVisibility = () => {
  44. if (passwordElement.value.type === "password") {
  45. passwordElement.value.type = "text";
  46. password.value.visible = true;
  47. } else {
  48. passwordElement.value.type = "password";
  49. password.value.visible = false;
  50. }
  51. };
  52. const changeToRegisterModal = () => {
  53. closeCurrentModal();
  54. openModal("register");
  55. };
  56. const githubRedirect = () => {
  57. localStorage.setItem("github_redirect", route.path);
  58. };
  59. const oidcRedirect = () => {
  60. localStorage.setItem("oidc_redirect", route.path);
  61. };
  62. </script>
  63. <template>
  64. <div>
  65. <modal
  66. title="Login"
  67. class="login-modal"
  68. :size="'slim'"
  69. @closed="closeCurrentModal()"
  70. >
  71. <template #body>
  72. <form>
  73. <!-- email address -->
  74. <p class="control">
  75. <label class="label">Username/Email</label>
  76. <input
  77. v-model="email"
  78. class="input"
  79. type="email"
  80. autocomplete="username"
  81. placeholder="Username/Email..."
  82. @input="checkForAutofill('email', $event)"
  83. @keyup.enter="submitModal()"
  84. />
  85. </p>
  86. <!-- password -->
  87. <p class="control">
  88. <label class="label">Password</label>
  89. </p>
  90. <div id="password-visibility-container">
  91. <input
  92. v-model="password.value"
  93. class="input"
  94. type="password"
  95. autocomplete="current-password"
  96. ref="passwordElement"
  97. placeholder="Password..."
  98. @input="checkForAutofill('password', $event)"
  99. @keyup.enter="submitModal()"
  100. />
  101. <a @click="togglePasswordVisibility()">
  102. <i class="material-icons">
  103. {{
  104. !password.visible
  105. ? "visibility"
  106. : "visibility_off"
  107. }}
  108. </i>
  109. </a>
  110. </div>
  111. <p
  112. v-if="configStore.mailEnabled"
  113. class="content-box-optional-helper"
  114. >
  115. <router-link
  116. id="forgot-password"
  117. to="/reset_password"
  118. @click="closeCurrentModal()"
  119. >
  120. Forgot password?
  121. </router-link>
  122. </p>
  123. <br />
  124. <p>
  125. By logging in you agree to our
  126. <router-link to="/terms" @click="closeCurrentModal()">
  127. Terms of Service
  128. </router-link>
  129. and
  130. <router-link to="/privacy" @click="closeCurrentModal()">
  131. Privacy Policy</router-link
  132. >.
  133. </p>
  134. </form>
  135. </template>
  136. <template #footer>
  137. <div id="actions">
  138. <button class="button is-primary" @click="submitModal()">
  139. Login
  140. </button>
  141. <a
  142. v-if="githubAuthentication"
  143. class="button is-github"
  144. :href="configStore.urls.api + '/auth/github/authorize'"
  145. @click="githubRedirect()"
  146. >
  147. <div class="icon">
  148. <img
  149. class="invert"
  150. src="/assets/social/github.svg"
  151. />
  152. </div>
  153. &nbsp;&nbsp;Login with GitHub
  154. </a>
  155. <a
  156. v-if="oidcAuthentication"
  157. class="button is-oidc"
  158. :href="configStore.urls.api + '/auth/oidc/authorize'"
  159. @click="oidcRedirect()"
  160. >
  161. <div class="icon">
  162. <img
  163. class="invert"
  164. src="/assets/social/github.svg"
  165. />
  166. </div>
  167. &nbsp;&nbsp;Login with OIDC
  168. </a>
  169. </div>
  170. <p
  171. v-if="!registrationDisabled"
  172. class="content-box-optional-helper"
  173. >
  174. <a @click="changeToRegisterModal()">
  175. Don't have an account?
  176. </a>
  177. </p>
  178. </template>
  179. </modal>
  180. </div>
  181. </template>
  182. <style lang="less" scoped>
  183. .night-mode {
  184. .modal-card,
  185. .modal-card-head,
  186. .modal-card-body,
  187. .modal-card-foot {
  188. background-color: var(--dark-grey-3);
  189. }
  190. .label,
  191. p:not(.help) {
  192. color: var(--light-grey-2);
  193. }
  194. }
  195. .modal-card-foot {
  196. display: flex;
  197. justify-content: space-between;
  198. flex-wrap: wrap;
  199. .content-box-optional-helper {
  200. margin-top: 0;
  201. }
  202. }
  203. .button.is-github {
  204. background-color: var(--dark-grey-2);
  205. color: var(--white) !important;
  206. }
  207. .is-github:focus {
  208. background-color: var(--dark-grey-4);
  209. }
  210. .is-primary:focus {
  211. background-color: var(--primary-color) !important;
  212. }
  213. .invert {
  214. filter: brightness(5);
  215. }
  216. </style>