useAddUnknownValueAction.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { email as emailValidation } from '@formkit/rules'
  3. import { ref, type Ref } from 'vue'
  4. import stopEvent from '#shared/utils/events.ts'
  5. import type { DropdownOptionsAction } from '#desktop/components/CommonSelect/types.ts'
  6. import type {
  7. AutoCompleteOptionValueDictionary,
  8. ClearFilterInputFunction,
  9. SelectOptionFunction,
  10. } from '#desktop/components/Form/fields/FieldAutoComplete/types.ts'
  11. import type { FormKitNode } from '@formkit/core'
  12. export const emailFilterValueValidator = (filter: string) =>
  13. emailValidation({ value: filter } as FormKitNode)
  14. export const phoneFilterValueValidator = (filter: string) =>
  15. /^\+?[1-9]\d+$/.test(filter)
  16. export const useAddUnknownValueAction = (
  17. label?: Ref<string>,
  18. filterValueValidator?: (filter: string) => boolean | Promise<boolean>,
  19. ) => {
  20. const actions = ref<DropdownOptionsAction[]>([])
  21. const actionLabel = label ?? ref(__('add new email address'))
  22. const isValidFilterValue = filterValueValidator ?? emailFilterValueValidator
  23. const isNewOption = (
  24. filter: string,
  25. optionValues: AutoCompleteOptionValueDictionary,
  26. ) => !optionValues[filter]
  27. const addUnknownValue = (
  28. filter: string,
  29. selectOption: SelectOptionFunction,
  30. clearFilter: ClearFilterInputFunction,
  31. focus: boolean,
  32. ) => {
  33. const newOption = {
  34. value: filter,
  35. label: filter,
  36. }
  37. selectOption(newOption, focus)
  38. clearFilter()
  39. }
  40. const onSearchInteractionUpdate = (
  41. filter: string,
  42. optionValues: AutoCompleteOptionValueDictionary,
  43. selectOption: SelectOptionFunction,
  44. clearFilter: ClearFilterInputFunction,
  45. ) => {
  46. if (!isNewOption(filter, optionValues) || !isValidFilterValue(filter)) {
  47. actions.value = []
  48. return
  49. }
  50. actions.value = [
  51. {
  52. key: 'addUnknownValue',
  53. label: actionLabel.value,
  54. icon: 'plus-square-fill',
  55. onClick: (focus) => {
  56. addUnknownValue(filter, selectOption, clearFilter, focus)
  57. // Reset actions after current filter was added.
  58. actions.value = []
  59. },
  60. },
  61. ]
  62. }
  63. const onKeydownFilterInput = (
  64. event: KeyboardEvent,
  65. filter: string,
  66. optionValues: AutoCompleteOptionValueDictionary,
  67. selectOption: SelectOptionFunction,
  68. clearFilter: ClearFilterInputFunction,
  69. ) => {
  70. const { key } = event
  71. if (!filter) return
  72. if (['Enter', 'Tab'].includes(key)) {
  73. stopEvent(event)
  74. if (!isNewOption(filter, optionValues) || !isValidFilterValue(filter))
  75. return
  76. addUnknownValue(filter, selectOption, clearFilter, true)
  77. }
  78. }
  79. return {
  80. actions,
  81. isNewOption,
  82. isValidFilterValue,
  83. addUnknownValue,
  84. onSearchInteractionUpdate,
  85. onKeydownFilterInput,
  86. }
  87. }