articleDelete.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. import { MutationHandler } from '@shared/server/apollo/handler'
  3. import type { ApolloCache } from '@apollo/client/cache'
  4. import type { InMemoryCache } from '@apollo/client/core'
  5. import { useTicketArticleDeleteMutation } from '@shared/entities/ticket-article/graphql/mutations/delete.api'
  6. import { useApplicationStore } from '@shared/stores/application'
  7. import { useSessionStore } from '@shared/stores/session'
  8. import type { TicketArticle, TicketById } from '@shared/entities/ticket/types'
  9. import useConfirmation from '@mobile/components/CommonConfirmation/composable'
  10. import { TicketArticlesDocument } from '@mobile/pages/ticket/graphql/queries/ticket/articles.api'
  11. import type { TicketArticleEdge } from '@shared/graphql/types'
  12. import type { TicketArticleActionPlugin, TicketArticleAction } from './types'
  13. const updateCacheAfterRemoving = (
  14. cache: ApolloCache<InMemoryCache>,
  15. ticket: TicketById,
  16. article: TicketArticle,
  17. ) => {
  18. const application = useApplicationStore()
  19. cache.updateQuery(
  20. {
  21. query: TicketArticlesDocument,
  22. variables: {
  23. ticketId: ticket.id,
  24. pageSize: Number(application.config.ticket_articles_min ?? 5),
  25. },
  26. },
  27. (data) => {
  28. const edges = data.articles.edges.filter(
  29. (elem: TicketArticleEdge) => elem.node.id !== article.id,
  30. )
  31. return {
  32. ...data,
  33. articles: {
  34. ...data.articles,
  35. edges,
  36. totalCount: data.articles.totalCount - 1,
  37. },
  38. }
  39. },
  40. )
  41. cache.gc()
  42. }
  43. const deleteAction = async (ticket: TicketById, article: TicketArticle) => {
  44. const { waitForConfirmation } = useConfirmation()
  45. const confirmed = await waitForConfirmation(
  46. __('Are you sure to remove this article?'),
  47. )
  48. if (!confirmed) return
  49. const mutation = new MutationHandler(
  50. useTicketArticleDeleteMutation({
  51. variables: { articleId: article.id },
  52. update(cache) {
  53. updateCacheAfterRemoving(cache, ticket, article)
  54. },
  55. }),
  56. { errorNotificationMessage: __('The article could not be deleted.') },
  57. )
  58. mutation.send()
  59. }
  60. const hasDeleteTimeframe = (deleteTimeframe: number) =>
  61. deleteTimeframe && deleteTimeframe > 0
  62. const secondsToDelete = (article: TicketArticle, deleteTimeframe: number) => {
  63. if (!hasDeleteTimeframe(deleteTimeframe)) return 0
  64. const now = new Date().getTime()
  65. const createdAt = new Date(article.createdAt).getTime()
  66. const secondsSinceCreated = (now - createdAt) / 1000
  67. if (secondsSinceCreated > deleteTimeframe) return 0
  68. return deleteTimeframe - secondsSinceCreated
  69. }
  70. const isDeletable = (article: TicketArticle, deleteTimeframe: number) => {
  71. const session = useSessionStore()
  72. if (article.createdBy?.id !== session.userId) return false
  73. if (article.type?.communication && !article.internal) return false
  74. if (
  75. hasDeleteTimeframe(deleteTimeframe) &&
  76. !secondsToDelete(article, deleteTimeframe)
  77. )
  78. return false
  79. return true
  80. }
  81. const actionPlugin: TicketArticleActionPlugin = {
  82. order: 999,
  83. addActions(ticket, article, { onDispose, recalculate, config }) {
  84. const deleteTimeframe =
  85. config.ui_ticket_zoom_article_delete_timeframe as number
  86. if (!isDeletable(article, deleteTimeframe)) return []
  87. const seconds = secondsToDelete(article, deleteTimeframe)
  88. if (seconds) {
  89. const timeout = window.setTimeout(() => {
  90. recalculate()
  91. }, seconds * 1_000)
  92. onDispose(() => {
  93. window.clearTimeout(timeout)
  94. })
  95. }
  96. const action: TicketArticleAction = {
  97. apps: ['mobile'],
  98. label: __('Delete Article'),
  99. name: 'articleDelete',
  100. icon: { mobile: 'trash' },
  101. perform: () => deleteAction(ticket, article),
  102. view: {
  103. agent: ['change'],
  104. },
  105. }
  106. return [action]
  107. },
  108. }
  109. export default actionPlugin