Login.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <!-- Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <template>
  3. <!-- TODO: Only a dummy implementation for the login... -->
  4. <div class="flex h-full min-h-screen flex-col items-center px-7 pt-7 pb-4">
  5. <div class="m-auto w-full max-w-md">
  6. <div class="flex grow flex-col justify-center">
  7. <div class="my-5 grow">
  8. <div class="flex justify-center p-2">
  9. <CommonLogo />
  10. </div>
  11. <div class="mb-6 flex justify-center p-2 text-2xl font-extrabold">
  12. {{ applicationConfig.value.product_name }}
  13. </div>
  14. <template v-if="applicationConfig.value.maintenance_login">
  15. <!-- eslint-disable vue/no-v-html -->
  16. <div
  17. class="my-1 flex items-center rounded-xl bg-green py-2 px-4 text-white"
  18. v-html="applicationConfig.value.maintenance_login_message"
  19. ></div>
  20. </template>
  21. <Form
  22. v-bind:schema="formSchema"
  23. class="text-left"
  24. v-on:submit="login"
  25. >
  26. <template v-slot:after-fields>
  27. <div class="mt-4 flex grow items-center justify-center">
  28. <span class="ltr:mr-1 rtl:ml-1">{{ i18n.t('New user?') }}</span>
  29. <CommonLink
  30. v-bind:link="'TODO'"
  31. class="cursor-pointer select-none !text-yellow underline"
  32. >{{ i18n.t('Register') }}</CommonLink
  33. >
  34. </div>
  35. <FormKit
  36. wrapper-class="mx-8 mt-8 flex grow justify-center items-center"
  37. input-class="py-2 px-4 w-full h-14 text-xl font-semibold text-black bg-yellow rounded-xl select-none"
  38. type="submit"
  39. >
  40. {{ i18n.t('Sign in') }}
  41. </FormKit>
  42. </template>
  43. </Form>
  44. </div>
  45. </div>
  46. </div>
  47. <div class="mb-6 flex items-center justify-center">
  48. <CommonLink link="TODO" class="!text-gray underline">
  49. {{ i18n.t('Continue to desktop app') }}
  50. </CommonLink>
  51. </div>
  52. <div class="flex items-center justify-center align-middle text-gray-200">
  53. <CommonLink
  54. link="https://zammad.org"
  55. is-external
  56. open-in-new-tab
  57. class="ltr:mr-1 rtl:ml-1"
  58. >
  59. <CommonIcon name="logo" v-bind:fixed-size="{ width: 24, height: 24 }" />
  60. </CommonLink>
  61. <span class="ltr:mr-1 rtl:ml-1">{{ i18n.t('Powered by') }}</span>
  62. <CommonLink
  63. link="https://zammad.org"
  64. is-external
  65. open-in-new-tab
  66. class="font-semibold !text-gray-200"
  67. >
  68. Zammad
  69. </CommonLink>
  70. </div>
  71. </div>
  72. </template>
  73. <script setup lang="ts">
  74. import useNotifications from '@common/composables/useNotifications'
  75. import useAuthenticationStore from '@common/stores/authenticated'
  76. import { useRouter } from 'vue-router'
  77. import { NotificationTypes } from '@common/types/notification'
  78. import CommonLogo from '@common/components/common/CommonLogo.vue'
  79. import useApplicationConfigStore from '@common/stores/application/config'
  80. import { i18n } from '@common/utils/i18n'
  81. import Form from '@common/components/form/Form.vue'
  82. import { FormData } from '@common/types/form'
  83. interface Props {
  84. invalidatedSession?: string
  85. }
  86. const props = defineProps<Props>()
  87. // Output a hint when the session is longer valid.
  88. // This could happen because because the session was deleted on the server.
  89. if (props.invalidatedSession === '1') {
  90. const { notify } = useNotifications()
  91. notify({
  92. message: __('The session is no longer valid. Please log in again.'),
  93. type: NotificationTypes.WARN,
  94. })
  95. }
  96. const authentication = useAuthenticationStore()
  97. const router = useRouter()
  98. const formSchema = [
  99. {
  100. type: 'text',
  101. name: 'login',
  102. label: __('Username / Email'),
  103. placeholder: __('Username / Email'),
  104. validation: 'required',
  105. },
  106. {
  107. type: 'password',
  108. label: __('Password'),
  109. name: 'password',
  110. placeholder: __('Password'),
  111. validation: 'required',
  112. },
  113. {
  114. isLayout: true,
  115. element: 'div',
  116. attrs: {
  117. class: 'mt-2.5 flex grow items-center justify-between text-white',
  118. },
  119. children: [
  120. {
  121. type: 'checkbox',
  122. label: __('Remember me'),
  123. name: 'remember_me',
  124. },
  125. {
  126. isLayout: true,
  127. component: 'CommonLink',
  128. props: {
  129. class: 'text-right !text-white',
  130. link: 'TODO',
  131. },
  132. children: i18n.t('Forgot password?'),
  133. },
  134. ],
  135. },
  136. ]
  137. interface LoginFormData {
  138. login?: string
  139. password?: string
  140. remember_me?: boolean
  141. }
  142. const login = (formData: FormData<LoginFormData>): void => {
  143. authentication
  144. .login(formData.login as string, formData.password as string)
  145. .then(() => {
  146. router.replace('/')
  147. })
  148. .catch((errors) => {
  149. const { notify } = useNotifications()
  150. notify({
  151. message: errors[0],
  152. type: NotificationTypes.ERROR,
  153. })
  154. })
  155. }
  156. const applicationConfig = useApplicationConfigStore()
  157. </script>