TicketDetailTopBar.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { computed, type ComputedRef, ref } from 'vue'
  4. import { useTicketChannel } from '#shared/entities/ticket/composables/useTicketChannel.ts'
  5. import { useTicketView } from '#shared/entities/ticket/composables/useTicketView.ts'
  6. import CommonBreadcrumb from '#desktop/components/CommonBreadcrumb/CommonBreadcrumb.vue'
  7. import { useMainLayoutContainer } from '#desktop/components/layout/composables/useMainLayoutContainer.ts'
  8. import { useCopyToClipboard } from '#desktop/composables/useCopyToClipboard.ts'
  9. import { useElementScroll } from '#desktop/composables/useElementScroll.ts'
  10. import HighlightMenu from '#desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/HighlightMenu.vue'
  11. import TicketInformation from '#desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TicketInformation.vue'
  12. import { useTicketInformation } from '#desktop/pages/ticket/composables/useTicketInformation.ts'
  13. import { useTicketNumber } from '#desktop/pages/ticket/composables/useTicketNumber.ts'
  14. const { ticket } = useTicketInformation()
  15. const { copyToClipboard } = useCopyToClipboard()
  16. const headerNode = ref<HTMLElement>()
  17. const { ticketNumber, ticketNumberWithTicketHook } = useTicketNumber(ticket)
  18. const items = computed(() => [
  19. // :TODO Adjust navigations currently two h1 are present
  20. {
  21. label: 'Tickets',
  22. to: { name: 'ticket-list' },
  23. },
  24. {
  25. label: ticketNumberWithTicketHook.value || '',
  26. noOptionLabelTranslation: true,
  27. to: { name: 'ticket-list' },
  28. },
  29. ])
  30. // Scroll Feature
  31. const { node: mainLayoutContainerElement } = useMainLayoutContainer()
  32. const { isScrollingDown: hideDetails } = useElementScroll(
  33. mainLayoutContainerElement as ComputedRef<HTMLElement>,
  34. {
  35. scrollStartThreshold: computed(() => headerNode.value?.clientHeight),
  36. },
  37. )
  38. const detailViewActiveClasses = computed(() => {
  39. if (hideDetails.value)
  40. return [
  41. 'ticket-detail-grid-compact gap-x-2 grid-cols-[1fr_max-content] items-center p-2 px-10',
  42. ]
  43. return [' ticket-detail-grid-full grid-cols-2 gap-y-2.5']
  44. })
  45. const alertViewActiveClasses = computed(() => {
  46. if (hideDetails.value) return ['top-[3.6rem]']
  47. return ['top-[8.75rem]']
  48. })
  49. const { isTicketAgent, isTicketEditable } = useTicketView(ticket)
  50. const { hasChannelAlert, channelAlert } = useTicketChannel(ticket)
  51. </script>
  52. <template>
  53. <header
  54. ref="headerNode"
  55. class="-:p-3 sticky top-0 z-10 grid border-b border-neutral-100 bg-neutral-50 dark:border-gray-900 dark:bg-gray-500"
  56. :class="detailViewActiveClasses"
  57. >
  58. <CommonBreadcrumb
  59. v-if="!hideDetails"
  60. emphasize-last-item
  61. size="small"
  62. :style="{ gridTemplate: 'breadcrumbs' }"
  63. :items="items"
  64. class="flex"
  65. >
  66. <template #trailing>
  67. <CommonIcon
  68. v-if="ticketNumber"
  69. v-tooltip="$t('Copy ticket number')"
  70. :aria-label="$t('Copy ticket number')"
  71. role="button"
  72. name="clipboard2"
  73. size="xs"
  74. class="cursor-pointer text-blue-800 ltr:ml-2 rtl:mr-2"
  75. @click="copyToClipboard(ticketNumberWithTicketHook)"
  76. />
  77. </template>
  78. </CommonBreadcrumb>
  79. <!-- TODO: we should have some computed for this policy thing or maybe we have already something? -->
  80. <HighlightMenu
  81. v-if="ticket?.policy?.update"
  82. class="justify-self-end"
  83. :style="{ gridTemplate: 'actions' }"
  84. />
  85. <TicketInformation
  86. v-if="ticket"
  87. :hide-details="hideDetails"
  88. :style="{ gridArea: hideDetails ? 'breadcrumbs' : 'info' }"
  89. :ticket="ticket"
  90. :class="{ 'mx-10': !hideDetails }"
  91. />
  92. </header>
  93. <CommonAlert
  94. v-if="isTicketAgent && isTicketEditable && hasChannelAlert"
  95. class="center sticky rounded-none px-14 transition-[top] duration-75 md:grid-cols-none md:justify-center"
  96. :class="alertViewActiveClasses"
  97. :variant="channelAlert?.variant"
  98. >
  99. {{ $t(channelAlert?.text, channelAlert?.textPlaceholder) }}
  100. </CommonAlert>
  101. </template>
  102. <style scoped>
  103. .ticket-detail-grid-full {
  104. grid-template-areas:
  105. 'breadcrumbs actions'
  106. 'info info';
  107. }
  108. .ticket-detail-grid-compact {
  109. grid-template-areas: 'breadcrumbs actions';
  110. }
  111. </style>