Login.vue 5.8 KB

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