useAlertFormHandler.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. import { createMessage } from '@formkit/core'
  3. import { FormHandlerExecution } from '#shared/components/Form/types.ts'
  4. import type {
  5. ChangedField,
  6. FormHandler,
  7. FormHandlerFunction,
  8. ReactiveFormSchemaDataField,
  9. ReactiveFormSchemData,
  10. } from '#shared/components/Form/types.ts'
  11. import type { FormKitMessage, FormKitNode } from '@formkit/core'
  12. export const useAlertFormHandler = (
  13. nodeName: string,
  14. message: Partial<FormKitMessage> & Pick<FormKitMessage, 'key'>,
  15. initialAddCallback: (
  16. field: ReactiveFormSchemaDataField,
  17. fields: Record<string, ReactiveFormSchemaDataField>,
  18. ) => boolean,
  19. changeAddCallback: (
  20. field: ChangedField | undefined,
  21. fields: Record<string, ReactiveFormSchemaDataField>,
  22. ) => boolean,
  23. eventHandler: (
  24. node: FormKitNode,
  25. addAlert: () => void,
  26. clearAlert: () => void,
  27. ) => void,
  28. eventName: string = 'input',
  29. ): FormHandler => {
  30. const addAlert = (formNode?: FormKitNode) => {
  31. formNode?.store.set(
  32. createMessage({
  33. blocking: false,
  34. type: 'warning',
  35. visible: true,
  36. ...message,
  37. }),
  38. )
  39. }
  40. const clearAlert = (formNode?: FormKitNode) => {
  41. formNode?.store.remove(message.key)
  42. }
  43. const initializeNodeEvent = (node: FormKitNode, formNode: FormKitNode) => {
  44. node.on(eventName, ({ origin }) => {
  45. eventHandler(
  46. origin,
  47. () => addAlert(formNode),
  48. () => clearAlert(formNode),
  49. )
  50. })
  51. }
  52. const initializeFormNodeEvents = (formNode: FormKitNode) => {
  53. formNode.on('child.deep', ({ payload }) => {
  54. const childNode = payload as FormKitNode
  55. if (childNode.name !== nodeName) return
  56. initializeNodeEvent(childNode, formNode)
  57. childNode.on('destroying', () => {
  58. clearAlert(formNode)
  59. })
  60. })
  61. }
  62. const initializeNodeEvents = (
  63. execution: FormHandlerExecution,
  64. getNodeByName: (id: string) => FormKitNode | undefined,
  65. formNode?: FormKitNode,
  66. ) => {
  67. if (execution === FormHandlerExecution.InitialSettled && formNode) {
  68. const node = getNodeByName(nodeName)
  69. if (node) {
  70. initializeNodeEvent(node, formNode)
  71. node.on('destroying', () => {
  72. clearAlert(formNode)
  73. initializeFormNodeEvents(formNode)
  74. })
  75. return
  76. }
  77. initializeFormNodeEvents(formNode)
  78. }
  79. }
  80. const executeHandler = (
  81. execution: FormHandlerExecution,
  82. schemaData: ReactiveFormSchemData,
  83. changedField?: ChangedField,
  84. formNode?: FormKitNode,
  85. ) => {
  86. if (
  87. schemaData.fields[nodeName] === undefined ||
  88. schemaData.fields[nodeName] === null ||
  89. (execution === FormHandlerExecution.FieldChange &&
  90. (!changedField || changedField.name !== nodeName)) ||
  91. (typeof formNode?.find === 'function' && !formNode?.find(nodeName))
  92. ) {
  93. return false
  94. }
  95. return true
  96. }
  97. const alertFormHandler: FormHandlerFunction = (
  98. execution,
  99. reactivity,
  100. data,
  101. ) => {
  102. const { changedField, formNode, getNodeByName } = data
  103. const { schemaData } = reactivity
  104. initializeNodeEvents(execution, getNodeByName, formNode)
  105. if (!executeHandler(execution, schemaData, changedField, formNode)) return
  106. if (
  107. (execution === FormHandlerExecution.InitialSettled &&
  108. initialAddCallback(schemaData.fields[nodeName], schemaData.fields)) ||
  109. (execution === FormHandlerExecution.FieldChange &&
  110. changeAddCallback(changedField, schemaData.fields))
  111. ) {
  112. addAlert(formNode)
  113. return
  114. }
  115. clearAlert(formNode)
  116. }
  117. return {
  118. execution: [
  119. FormHandlerExecution.InitialSettled,
  120. FormHandlerExecution.FieldChange,
  121. ],
  122. callback: alertFormHandler,
  123. }
  124. }