FavoriteTicketOverviewsEdit.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <!-- Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { animations, updateConfig } from '@formkit/drag-and-drop'
  4. import { dragAndDrop } from '@formkit/drag-and-drop/vue'
  5. import { storeToRefs } from 'pinia'
  6. import { computed, ref, watch } from 'vue'
  7. import {
  8. NotificationTypes,
  9. useNotifications,
  10. } from '#shared/components/CommonNotifications/index.ts'
  11. import { useWalker } from '#shared/router/walker.ts'
  12. import CommonSectionMenu from '#mobile/components/CommonSectionMenu/CommonSectionMenu.vue'
  13. import { useHeader } from '#mobile/composables/useHeader.ts'
  14. import { useTicketOverviewOrderStore } from '#mobile/entities/ticket/stores/ticketOverviewOrder.ts'
  15. import { useTicketOverviewsStore } from '#mobile/entities/ticket/stores/ticketOverviews.ts'
  16. import TicketOverviewEditItem from '../components/TicketOverviewEditItem.vue'
  17. const overviewOrderStore = useTicketOverviewOrderStore()
  18. const {
  19. overviews,
  20. loading: overviewsLoading,
  21. overviewsByKey,
  22. } = storeToRefs(overviewOrderStore)
  23. // we store local included, so they won't affect home page
  24. const includedIds = ref(new Set(overviewOrderStore.includedIds.values()))
  25. watch(
  26. // when overviews are loaded, updated local included
  27. () => overviewOrderStore.includedIds,
  28. (ids) => {
  29. includedIds.value = ids
  30. },
  31. )
  32. const includedOverviews = computed({
  33. get: () => {
  34. return [...includedIds.value]
  35. .map((id) => overviewsByKey.value[id])
  36. .filter(Boolean)
  37. },
  38. set: (value) => {
  39. includedIds.value = new Set(value.map((overview) => overview.id))
  40. },
  41. })
  42. const dndParentRef = ref()
  43. dragAndDrop({
  44. parent: dndParentRef,
  45. values: includedOverviews,
  46. plugins: [animations()],
  47. dropZoneClass: 'opacity-0',
  48. touchDropZoneClass: 'opacity-0',
  49. })
  50. const { notify } = useNotifications()
  51. const walker = useWalker()
  52. useHeader({
  53. title: __('Ticket Overview'),
  54. backUrl: '/',
  55. backAvoidHomeButton: true,
  56. actionTitle: __('Save'),
  57. onAction() {
  58. if (!includedOverviews.value.length) {
  59. notify({
  60. id: 'no-overview',
  61. message: __('Please select at least one ticket overview'),
  62. type: NotificationTypes.Error,
  63. })
  64. return
  65. }
  66. overviewOrderStore.saveOverviews(includedOverviews.value)
  67. useTicketOverviewsStore().updateOverviews(includedOverviews.value)
  68. notify({
  69. id: 'overview-save',
  70. message: __('Ticket Overview settings are saved.'),
  71. type: NotificationTypes.Success,
  72. })
  73. walker.back('/')
  74. },
  75. })
  76. const excludedOverviews = computed(() => {
  77. return overviews.value.filter(
  78. (overview) => !includedIds.value.has(overview.id),
  79. )
  80. })
  81. const removeFromFavorites = (id: string) => {
  82. includedIds.value.delete(id)
  83. }
  84. const addToFavorites = (id: string) => {
  85. includedIds.value.add(id)
  86. }
  87. const updateDndDisabledConfig = (disabled: boolean) => {
  88. updateConfig(dndParentRef.value, { disabled })
  89. }
  90. </script>
  91. <template>
  92. <div class="mx-4 mt-6">
  93. <div v-if="overviewsLoading" class="flex items-center justify-center">
  94. <CommonIcon name="loading" animation="spin" />
  95. </div>
  96. <CommonSectionMenu
  97. v-if="!overviewsLoading"
  98. :header-label="__('Included ticket overviews')"
  99. data-test-id="includedOverviews"
  100. >
  101. <div ref="dndParentRef">
  102. <TicketOverviewEditItem
  103. v-for="overview in includedOverviews"
  104. :key="overview.id"
  105. action="delete"
  106. :overview="overview"
  107. draggable
  108. @action="removeFromFavorites(overview.id)"
  109. @action-active="updateDndDisabledConfig"
  110. />
  111. </div>
  112. <div
  113. v-if="!includedOverviews.length"
  114. class="ms-3 flex min-h-[54px] items-center"
  115. >
  116. <p>{{ $t('No entries') }}</p>
  117. </div>
  118. </CommonSectionMenu>
  119. <CommonSectionMenu
  120. v-if="!overviewsLoading"
  121. :header-label="__('More ticket overviews')"
  122. data-test-id="excludedOverviews"
  123. >
  124. <TicketOverviewEditItem
  125. v-for="overview of excludedOverviews"
  126. :key="overview.id"
  127. action="add"
  128. :overview="overview"
  129. @action="addToFavorites(overview.id)"
  130. />
  131. <div
  132. v-if="!excludedOverviews.length"
  133. class="ms-3 flex min-h-[54px] items-center"
  134. >
  135. <p>{{ $t('No entries') }}</p>
  136. </div>
  137. </CommonSectionMenu>
  138. </div>
  139. </template>