index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { useState } from 'react'
  2. import Operate from './Operate'
  3. import KeyInput from './KeyInput'
  4. import { useValidate } from './hooks'
  5. import type { Form, KeyFrom, Status, ValidateValue } from './declarations'
  6. import { useEventEmitterContextContext } from '@/context/event-emitter'
  7. import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
  8. export type KeyValidatorProps = {
  9. type: string
  10. title: React.ReactNode
  11. status: Status
  12. forms: Form[]
  13. keyFrom: KeyFrom
  14. onSave: (v: ValidateValue) => Promise<boolean | undefined>
  15. disabled?: boolean
  16. }
  17. const KeyValidator = ({
  18. type,
  19. title,
  20. status,
  21. forms,
  22. keyFrom,
  23. onSave,
  24. disabled,
  25. }: KeyValidatorProps) => {
  26. const triggerKey = `plugins/${type}`
  27. const { eventEmitter } = useEventEmitterContextContext()
  28. const [isOpen, setIsOpen] = useState(false)
  29. const prevValue = forms.reduce((prev: ValidateValue, next: Form) => {
  30. prev[next.key] = next.value
  31. return prev
  32. }, {})
  33. const [value, setValue] = useState(prevValue)
  34. const [validate, validating, validatedStatusState] = useValidate(value)
  35. eventEmitter?.useSubscription((v) => {
  36. if (v !== triggerKey) {
  37. setIsOpen(false)
  38. setValue(prevValue)
  39. validate({ before: () => false })
  40. }
  41. })
  42. const handleCancel = () => {
  43. eventEmitter?.emit('')
  44. }
  45. const handleSave = async () => {
  46. if (await onSave(value))
  47. eventEmitter?.emit('')
  48. }
  49. const handleAdd = () => {
  50. setIsOpen(true)
  51. eventEmitter?.emit(triggerKey)
  52. }
  53. const handleEdit = () => {
  54. setIsOpen(true)
  55. eventEmitter?.emit(triggerKey)
  56. }
  57. const handleChange = (form: Form, val: string) => {
  58. setValue({ ...value, [form.key]: val })
  59. if (form.validate)
  60. validate(form.validate)
  61. }
  62. const handleFocus = (form: Form) => {
  63. if (form.handleFocus)
  64. form.handleFocus(value, setValue)
  65. }
  66. return (
  67. <div className='mb-2 border-[0.5px] border-gray-200 bg-gray-50 rounded-md'>
  68. <div className={
  69. `flex items-center justify-between px-4 h-[52px] cursor-pointer ${isOpen && 'border-b-[0.5px] border-b-gray-200'}`
  70. }>
  71. {title}
  72. <Operate
  73. isOpen={isOpen}
  74. status={status}
  75. onCancel={handleCancel}
  76. onSave={handleSave}
  77. onAdd={handleAdd}
  78. onEdit={handleEdit}
  79. disabled={disabled}
  80. />
  81. </div>
  82. {
  83. isOpen && !disabled && (
  84. <div className='px-4 py-3'>
  85. {
  86. forms.map(form => (
  87. <KeyInput
  88. key={form.key}
  89. className='mb-4'
  90. name={form.title}
  91. placeholder={form.placeholder}
  92. value={value[form.key] as string || ''}
  93. onChange={v => handleChange(form, v)}
  94. onFocus={() => handleFocus(form)}
  95. validating={validating}
  96. validatedStatusState={validatedStatusState}
  97. />
  98. ))
  99. }
  100. <a className="flex items-center text-xs cursor-pointer text-primary-600" href={keyFrom.link} target='_blank' rel='noopener noreferrer'>
  101. {keyFrom.text}
  102. <LinkExternal02 className='w-3 h-3 ml-1 text-primary-600' />
  103. </a>
  104. </div>
  105. )
  106. }
  107. </div>
  108. )
  109. }
  110. export default KeyValidator