FieldCustomerWrapper.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { pick } from 'lodash-es'
  4. import { markRaw } from 'vue'
  5. import type { SelectValue } from '#shared/components/CommonSelect/types.ts'
  6. import type { AutoCompleteOption } from '#shared/components/Form/fields/FieldAutocomplete/types.ts'
  7. import { AutocompleteSearchGenericDocument } from '#shared/components/Form/fields/FieldCustomer/graphql/queries/autocompleteSearch/generic.api.ts'
  8. import type { AutoCompleteCustomerGenericOption } from '#shared/components/Form/fields/FieldCustomer/types.ts'
  9. import type { FormFieldContext } from '#shared/components/Form/types/field.ts'
  10. import type { User } from '#shared/graphql/types.ts'
  11. import type { ObjectLike } from '#shared/types/utils.ts'
  12. import { normalizeEdges } from '#shared/utils/helpers.ts'
  13. import FieldAutoCompleteInput from '../FieldAutoComplete/FieldAutoCompleteInput.vue'
  14. import { useAddUnknownValueAction } from '../FieldAutoComplete/useAddUnknownValueAction.ts'
  15. import FieldCustomerOptionIcon from './FieldCustomerOptionIcon.vue'
  16. import type { AutoCompleteProps } from '../FieldAutoComplete/types.ts'
  17. interface Props {
  18. context: FormFieldContext<
  19. AutoCompleteProps & {
  20. options?: AutoCompleteCustomerGenericOption[]
  21. }
  22. >
  23. }
  24. const props = defineProps<Props>()
  25. const buildEntityOption = (entity: User) => {
  26. return {
  27. value: entity.internalId,
  28. label: entity.fullname || entity.phone || entity.login,
  29. heading: entity.organization?.name,
  30. user: entity,
  31. }
  32. }
  33. const { actions, onSearchInteractionUpdate, onKeydownFilterInput } =
  34. useAddUnknownValueAction()
  35. Object.assign(props.context, {
  36. optionIconComponent: markRaw(FieldCustomerOptionIcon),
  37. initialOptionBuilder: (
  38. initialEntityObject: ObjectLike,
  39. value: SelectValue,
  40. context: Props['context'],
  41. ) => {
  42. if (!context.belongsToObjectField || !initialEntityObject) return null
  43. const belongsToObject = initialEntityObject[context.belongsToObjectField]
  44. if (!belongsToObject) return null
  45. return buildEntityOption(belongsToObject)
  46. },
  47. gqlQuery: AutocompleteSearchGenericDocument,
  48. additionalQueryParams: {
  49. onlyIn: ['User', 'Organization'],
  50. },
  51. autocompleteOptionsPreprocessor: (
  52. autocompleteOptions: (AutoCompleteCustomerGenericOption &
  53. AutoCompleteOption)[],
  54. ) =>
  55. autocompleteOptions.map((autocompleteOption) => {
  56. if (
  57. !autocompleteOption.object ||
  58. autocompleteOption.object.__typename !== 'Organization'
  59. )
  60. return autocompleteOption
  61. autocompleteOption.disabled = true
  62. const heading = autocompleteOption.object.name
  63. const allMembers = normalizeEdges(autocompleteOption.object.allMembers)
  64. autocompleteOption.children =
  65. allMembers.array.map(
  66. (member) =>
  67. ({
  68. value: member.internalId,
  69. label: member.fullname ?? member.phone ?? member.login,
  70. heading,
  71. object: {
  72. ...member,
  73. __typename: 'User',
  74. // Include the current organization only, so the organization field can be automatically pre-filled.
  75. // This can potentially be a secondary organization of the user, depending on the current navigation.
  76. organization: pick(autocompleteOption.object, [
  77. '__typename',
  78. 'id',
  79. 'internalId',
  80. 'name',
  81. 'active',
  82. ]),
  83. },
  84. }) as AutoCompleteOption,
  85. ) || []
  86. return autocompleteOption
  87. }),
  88. actions,
  89. emptyInitialLabelText: __(
  90. 'Start typing to search or enter an email address…',
  91. ),
  92. })
  93. </script>
  94. <template>
  95. <FieldAutoCompleteInput
  96. :context="context"
  97. v-bind="$attrs"
  98. @search-interaction-update="onSearchInteractionUpdate"
  99. @keydown-filter-input="onKeydownFilterInput"
  100. />
  101. </template>