useTicketsMerge.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. import type { FormKitNode } from '@formkit/core'
  3. import useConfirmation from '@mobile/components/CommonConfirmation/composable'
  4. import {
  5. useNotifications,
  6. NotificationTypes,
  7. } from '@shared/components/CommonNotifications'
  8. import { useDialog } from '@shared/composables/useDialog'
  9. import UserError from '@shared/errors/UserError'
  10. import { MutationHandler } from '@shared/server/apollo/handler'
  11. import type { Ref } from 'vue'
  12. import { ref, markRaw } from 'vue'
  13. import { useRouter } from 'vue-router'
  14. import { useTicketMergeMutation } from '@shared/entities/ticket/graphql/mutations/merge.api'
  15. import type { AutocompleteSearchMergeTicketEntry } from '@shared/graphql/types'
  16. import { keyBy } from 'lodash-es'
  17. import type { TicketById } from '@shared/entities/ticket/types'
  18. import { AutocompleteSearchMergeTicketDocument } from '../graphql/queries/autocompleteSearchMergeTicket.api'
  19. import TicketMergeStatus from '../components/TicketDetailView/TicketMergeStatus.vue'
  20. export const useTicketsMerge = (
  21. sourceTicket: Ref<TicketById>,
  22. onSuccess?: () => void,
  23. ) => {
  24. const autocompleteRef = ref<{ node: FormKitNode }>()
  25. const ticketsSearchDialog = useDialog({
  26. name: 'tickets-search',
  27. prefetch: true,
  28. component: () =>
  29. import(
  30. '@shared/components/Form/fields/FieldAutoComplete/FieldAutoCompleteInputDialog.vue'
  31. ),
  32. })
  33. const mergeHandler = new MutationHandler(useTicketMergeMutation({}))
  34. const { notify } = useNotifications()
  35. const router = useRouter()
  36. const { waitForConfirmation } = useConfirmation()
  37. let localOptions: Record<string, AutocompleteSearchMergeTicketEntry> = {}
  38. const mergeTickets = async () => {
  39. const context = autocompleteRef.value?.node.context
  40. if (!context || mergeHandler.loading().value) return false
  41. const targetTicketId = context._value
  42. const targetTicketOption = localOptions[targetTicketId]
  43. if (!targetTicketId || !targetTicketOption) {
  44. notify({
  45. type: NotificationTypes.Error,
  46. message: __('Please select a ticket to merge into.'),
  47. })
  48. return false
  49. }
  50. const targetTicket = targetTicketOption.ticket
  51. const confirmed = await waitForConfirmation(
  52. __('Are you sure you want to merge this ticket (#%s) into #%s?'),
  53. {
  54. headingPlaceholder: [sourceTicket.value.number, targetTicket.number],
  55. },
  56. )
  57. if (!confirmed) return false
  58. try {
  59. const result = await mergeHandler.send({
  60. sourceTicketId: sourceTicket.value.id,
  61. targetTicketId,
  62. })
  63. if (!result) {
  64. return false
  65. }
  66. context.node.input(undefined)
  67. router.push(`/tickets/${targetTicket.internalId}`)
  68. return true
  69. } catch (errors) {
  70. if (errors instanceof UserError) {
  71. notify({
  72. message: errors.generalErrors[0],
  73. type: NotificationTypes.Error,
  74. })
  75. }
  76. }
  77. return false
  78. }
  79. const mergeAndCloseModals = async () => {
  80. const isMerged = await mergeTickets()
  81. if (isMerged) {
  82. ticketsSearchDialog.close()
  83. onSuccess?.()
  84. }
  85. }
  86. const openMergeTicketsDialog = () => {
  87. const context = autocompleteRef.value?.node.context
  88. if (!context) return
  89. Object.assign(context, {
  90. onActionClick: mergeAndCloseModals,
  91. })
  92. ticketsSearchDialog.open({
  93. context,
  94. name: 'tickets-search',
  95. options: [],
  96. optionIconComponent: markRaw(TicketMergeStatus),
  97. noCloseOnSelect: true,
  98. onUpdateOptions(options: AutocompleteSearchMergeTicketEntry[]) {
  99. localOptions = keyBy(options, 'value')
  100. },
  101. onAction() {
  102. mergeAndCloseModals()
  103. },
  104. })
  105. }
  106. return {
  107. gqlQuery: AutocompleteSearchMergeTicketDocument,
  108. autocompleteRef,
  109. openMergeTicketsDialog,
  110. }
  111. }