useTicketArticlesRows.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { controlledComputed } from '@vueuse/shared'
  3. import type { TicketArticle } from '#shared/entities/ticket/types.ts'
  4. import { EnumTicketArticleSenderName } from '#shared/graphql/types.ts'
  5. import { i18n } from '#shared/i18n.ts'
  6. import { useSessionStore } from '#shared/stores/session.ts'
  7. import { useTicketInformation } from './useTicketInformation.ts'
  8. import type { Ref } from 'vue'
  9. interface ArticleRow {
  10. type: 'article-bubble'
  11. article: TicketArticle
  12. }
  13. interface ArticleDeliveryRow {
  14. type: 'delivery'
  15. content: string
  16. }
  17. interface MoreRow {
  18. type: 'more'
  19. count: number
  20. }
  21. interface NewRow {
  22. type: 'new'
  23. }
  24. interface DateRow {
  25. type: 'date'
  26. date: string
  27. }
  28. interface SystemRaw {
  29. type: 'system'
  30. subject?: Maybe<string>
  31. to?: Maybe<string>
  32. }
  33. type TicketArticleRow = (
  34. | ArticleRow
  35. | SystemRaw
  36. | MoreRow
  37. | NewRow
  38. | DateRow
  39. | ArticleDeliveryRow
  40. ) & {
  41. key: string
  42. }
  43. export const useTicketArticleRows = (
  44. articles: Ref<TicketArticle[]>,
  45. totalCount: Ref<number>,
  46. ) => {
  47. const { newArticlesIds } = useTicketInformation()
  48. const session = useSessionStore()
  49. const rows = controlledComputed(articles, () => {
  50. const rows: TicketArticleRow[] = []
  51. const dates = new Set<string>()
  52. const needMoreButton = articles.value.length < totalCount.value
  53. let hasNew = false
  54. // assuming it is sorted by createdAt
  55. articles.value.forEach((article, index) => {
  56. const date = i18n.date(article.createdAt)
  57. if (!dates.has(date)) {
  58. dates.add(date)
  59. rows.push({
  60. type: 'date',
  61. date: article.createdAt,
  62. key: date,
  63. })
  64. }
  65. if (article.preferences?.delivery_message) {
  66. rows.push({
  67. type: 'delivery',
  68. content: article.bodyWithUrls,
  69. key: article.id,
  70. })
  71. } else if (
  72. article.sender?.name === EnumTicketArticleSenderName.System &&
  73. article.type?.name !== 'note'
  74. ) {
  75. rows.push({
  76. type: 'system',
  77. subject: article.subject,
  78. to: article.to?.raw || '',
  79. key: article.id,
  80. })
  81. } else {
  82. rows.push({
  83. type: 'article-bubble',
  84. article,
  85. key: article.id,
  86. })
  87. }
  88. // after "description" (always first) article is added, add "more" button
  89. if (index === 0 && needMoreButton) {
  90. rows.push({
  91. type: 'more',
  92. key: 'more',
  93. count: totalCount.value - articles.value.length,
  94. })
  95. }
  96. const next = articles.value[index + 1]
  97. if (
  98. !hasNew &&
  99. next &&
  100. session.userId !== next.author.id &&
  101. newArticlesIds.has(next.id)
  102. ) {
  103. hasNew = true
  104. rows.push({
  105. type: 'new',
  106. key: 'new',
  107. })
  108. }
  109. })
  110. return rows
  111. })
  112. return { rows }
  113. }