PasswordResetVerify.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { ref, onBeforeMount } from 'vue'
  4. import { useRouter } from 'vue-router'
  5. import { NotificationTypes } from '#shared/components/CommonNotifications/types.ts'
  6. import { useNotifications } from '#shared/components/CommonNotifications/useNotifications.ts'
  7. import Form from '#shared/components/Form/Form.vue'
  8. import type {
  9. FormSchemaNode,
  10. FormSubmitData,
  11. } from '#shared/components/Form/types.ts'
  12. import { useForm } from '#shared/components/Form/useForm.ts'
  13. import { EnumPublicLinksScreen } from '#shared/graphql/types.ts'
  14. import MutationHandler from '#shared/server/apollo/handler/MutationHandler.ts'
  15. import { useApplicationStore } from '#shared/stores/application.ts'
  16. import CommonButton from '#desktop/components/CommonButton/CommonButton.vue'
  17. import CommonLoader from '#desktop/components/CommonLoader/CommonLoader.vue'
  18. import CommonPublicLinks from '#desktop/components/CommonPublicLinks/CommonPublicLinks.vue'
  19. import LayoutPublicPage from '#desktop/components/layout/LayoutPublicPage/LayoutPublicPage.vue'
  20. import { useUserPasswordResetUpdateMutation } from '../graphql/mutations/userPasswordResetUpdate.api.ts'
  21. import { useUserPasswordResetVerifyMutation } from '../graphql/mutations/userPasswordResetVerify.api.ts'
  22. defineOptions({
  23. beforeRouteEnter(to) {
  24. const application = useApplicationStore()
  25. if (!application.config.user_lost_password) {
  26. return to.redirectedFrom ? false : '/'
  27. }
  28. return true
  29. },
  30. })
  31. interface Props {
  32. token?: string
  33. }
  34. const props = defineProps<Props>()
  35. interface FormValues {
  36. password: string
  37. confirmPassword: string
  38. }
  39. const formSchema: FormSchemaNode[] = [
  40. {
  41. type: 'password',
  42. label: __('Password'),
  43. name: 'password',
  44. outerClass: 'col-span-1',
  45. required: true,
  46. props: {
  47. maxLength: 1001,
  48. },
  49. },
  50. {
  51. type: 'password',
  52. label: __('Confirm password'),
  53. name: 'password_confirm',
  54. outerClass: 'col-span-1',
  55. validation: 'confirm',
  56. props: {
  57. maxLength: 1001,
  58. },
  59. required: true,
  60. },
  61. ]
  62. const { form, isDisabled } = useForm()
  63. const errorMessage = ref('')
  64. const loading = ref(true)
  65. const canResetPassword = ref(false)
  66. const { notify } = useNotifications()
  67. const router = useRouter()
  68. onBeforeMount(() => {
  69. if (!props.token) {
  70. loading.value = false
  71. canResetPassword.value = false
  72. errorMessage.value = __(
  73. 'The token could not be verified. Please contact your administrator.',
  74. )
  75. return
  76. }
  77. const userSignupVerify = new MutationHandler(
  78. useUserPasswordResetVerifyMutation({
  79. variables: { token: props.token },
  80. }),
  81. {
  82. errorShowNotification: false,
  83. },
  84. )
  85. userSignupVerify
  86. .send()
  87. .then(() => {
  88. canResetPassword.value = true
  89. errorMessage.value = ''
  90. })
  91. .catch(() => {
  92. canResetPassword.value = false
  93. errorMessage.value = __('The provided token is invalid.')
  94. })
  95. .finally(() => {
  96. loading.value = false
  97. })
  98. })
  99. const resetPasswordHandler = new MutationHandler(
  100. useUserPasswordResetUpdateMutation(),
  101. { errorShowNotification: false },
  102. )
  103. const updatePassword = async (form: FormSubmitData<FormValues>) => {
  104. await resetPasswordHandler.send({
  105. token: props.token!,
  106. password: form.password,
  107. })
  108. notify({
  109. id: 'password-change',
  110. type: NotificationTypes.Success,
  111. message: __('Woo hoo! Your password has been changed!'),
  112. })
  113. router.replace('/login')
  114. }
  115. const goToLogin = () => {
  116. router.replace('/login')
  117. }
  118. </script>
  119. <template>
  120. <LayoutPublicPage box-size="medium" :title="__('Choose your new password')">
  121. <CommonLoader :loading="loading" :error="errorMessage" />
  122. <Form
  123. v-if="canResetPassword"
  124. id="password-reset-verify"
  125. ref="form"
  126. form-class="mb-2.5 grid grid-cols-2 gap-y-2.5 gap-x-3"
  127. :schema="formSchema"
  128. @submit="updatePassword($event as FormSubmitData<FormValues>)"
  129. />
  130. <template #boxActions>
  131. <CommonButton
  132. variant="secondary"
  133. size="medium"
  134. :disabled="isDisabled"
  135. @click="goToLogin()"
  136. >
  137. {{ $t('Cancel & Go Back') }}
  138. </CommonButton>
  139. <CommonButton
  140. v-if="canResetPassword"
  141. type="submit"
  142. variant="submit"
  143. size="medium"
  144. form="password-reset-verify"
  145. :disabled="isDisabled"
  146. >
  147. {{ $t('Submit') }}
  148. </CommonButton>
  149. </template>
  150. <template #bottomContent>
  151. <CommonPublicLinks :screen="EnumPublicLinksScreen.PasswordReset" />
  152. </template>
  153. </LayoutPublicPage>
  154. </template>