usePopoverMenu.ts 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { inject, computed, provide } from 'vue'
  3. import { useSessionStore } from '#shared/stores/session.ts'
  4. import type { ObjectLike } from '#shared/types/utils.ts'
  5. import getUuid from '#shared/utils/getUuid.ts'
  6. import type {
  7. GroupItem,
  8. MenuItem,
  9. MenuItems,
  10. UsePopoverMenuReturn,
  11. } from '#desktop/components/CommonPopoverMenu/types.ts'
  12. import type { Ref } from 'vue'
  13. const POPOVER_MENU_SYMBOL = Symbol('popover-menu')
  14. export const usePopoverMenu = (
  15. items: Ref<MenuItem[] | undefined>,
  16. entity: Ref<ObjectLike | undefined>,
  17. options: { provides?: boolean } = {},
  18. ) => {
  19. const injectPopoverMenu = inject<Maybe<UsePopoverMenuReturn>>(
  20. POPOVER_MENU_SYMBOL,
  21. null,
  22. )
  23. if (injectPopoverMenu) return injectPopoverMenu
  24. const { provides = false } = options
  25. const session = useSessionStore()
  26. const filterItems = () => {
  27. return items.value?.filter((item) => {
  28. if (item.permission && item.show) {
  29. return (
  30. session.hasPermission(item.permission) && item.show(entity?.value)
  31. )
  32. }
  33. if (item.permission) {
  34. return session.hasPermission(item.permission)
  35. }
  36. if (item.show) {
  37. return item.show(entity?.value)
  38. }
  39. return true
  40. })
  41. }
  42. const filteredMenuItems = computed(() => {
  43. if (!items.value || !items.value.length) return
  44. const filteredItems = filterItems()
  45. return filteredItems?.reduce((acc: MenuItems, item) => {
  46. if (!item.groupLabel) {
  47. acc.push(item)
  48. return acc
  49. }
  50. const foundedItem = acc.find(
  51. (group) => group.groupLabel === item.groupLabel,
  52. )
  53. const { groupLabel, ...rest } = item
  54. if (!foundedItem) acc.push({ groupLabel, key: getUuid(), array: [rest] })
  55. else (foundedItem as GroupItem).array.push(rest)
  56. return acc
  57. }, [])
  58. })
  59. const singleMenuItemPresent = computed(() => {
  60. return filteredMenuItems.value?.length === 1
  61. })
  62. const singleMenuItem = computed(() => {
  63. if (!singleMenuItemPresent.value) return
  64. return filterItems()?.at(0)
  65. })
  66. const providePopoverMenu = {
  67. filteredMenuItems,
  68. singleMenuItemPresent,
  69. singleMenuItem,
  70. }
  71. if (provides) provide(POPOVER_MENU_SYMBOL, providePopoverMenu)
  72. return providePopoverMenu
  73. }