useTicketArticleReply.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { computed, ref } from 'vue'
  3. import { useRoute } from 'vue-router'
  4. import type { FormRef } from '#shared/components/Form/types.ts'
  5. import type { TicketById } from '#shared/entities/ticket/types.ts'
  6. import { useDialog } from '#mobile/composables/useDialog.ts'
  7. import type { Ref, ShallowRef } from 'vue'
  8. interface ReplyDialogOptions {
  9. updateFormLocation: (location: string) => void
  10. }
  11. export const useTicketArticleReply = (
  12. ticket: Ref<TicketById | undefined>,
  13. form: ShallowRef<FormRef | undefined>,
  14. needSpaceForSaveBanner: Ref<boolean>,
  15. ) => {
  16. const newTicketArticleRequested = ref(false)
  17. const newTicketArticlePresent = ref(false)
  18. const articleFormGroupNode = computed(() => {
  19. if (!newTicketArticlePresent.value && !newTicketArticleRequested.value)
  20. return undefined
  21. return form.value?.getNodeByName('article')
  22. })
  23. const isArticleFormGroupValid = computed(() => {
  24. return !!articleFormGroupNode.value?.context?.state.valid
  25. })
  26. const articleReplyDialog = useDialog({
  27. name: 'ticket-article-reply',
  28. component: () =>
  29. import(
  30. '#mobile/pages/ticket/components/TicketDetailView/ArticleReplyDialog.vue'
  31. ),
  32. beforeOpen: () => {
  33. newTicketArticleRequested.value = true
  34. },
  35. afterClose: () => {
  36. newTicketArticleRequested.value = false
  37. },
  38. })
  39. const rememberArticleFormGroup = () => {
  40. newTicketArticlePresent.value = true
  41. }
  42. const route = useRoute()
  43. const resetDirtyTicketState = () => {
  44. const stateId = form.value?.getNodeByName('state_id')
  45. const isDefaultFollowUpStateSet = form.value?.getNodeByName(
  46. 'isDefaultFollowUpStateSet',
  47. )
  48. if (
  49. !stateId ||
  50. !isDefaultFollowUpStateSet ||
  51. !isDefaultFollowUpStateSet.value
  52. )
  53. return false
  54. // If the default follow-up state was set, then we want to reset the state on article discard.
  55. // See `app/models/form_updater/updater/ticket/edit.rb` for more info.
  56. stateId.reset()
  57. isDefaultFollowUpStateSet.reset()
  58. return true
  59. }
  60. const openArticleReplyDialog = async ({
  61. updateFormLocation,
  62. }: ReplyDialogOptions) => {
  63. if (!ticket.value) return
  64. return articleReplyDialog.open({
  65. name: articleReplyDialog.name,
  66. ticket,
  67. form,
  68. needSpaceForSaveBanner,
  69. newTicketArticlePresent,
  70. articleFormGroupNode,
  71. updateFormLocation,
  72. onDone() {
  73. rememberArticleFormGroup()
  74. },
  75. onDiscard() {
  76. newTicketArticlePresent.value = false
  77. resetDirtyTicketState()
  78. },
  79. onShowArticleForm() {
  80. updateFormLocation('[data-ticket-article-reply-form]')
  81. },
  82. onHideArticleForm() {
  83. if (route.name === 'TicketInformationDetails') {
  84. updateFormLocation('[data-ticket-edit-form]')
  85. return
  86. }
  87. updateFormLocation('body')
  88. },
  89. })
  90. }
  91. const closeArticleReplyDialog = (rememberArticle = false) => {
  92. if (rememberArticle) rememberArticleFormGroup()
  93. return articleReplyDialog.close()
  94. }
  95. return {
  96. articleReplyDialog,
  97. newTicketArticleRequested,
  98. newTicketArticlePresent,
  99. articleFormGroupNode,
  100. isArticleFormGroupValid,
  101. openArticleReplyDialog,
  102. closeArticleReplyDialog,
  103. }
  104. }