CustomParamField.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import React, { useRef } from 'react';
  2. import { ErrorMessage } from '@hookform/error-message';
  3. import { TOPIC_CUSTOM_PARAMS } from 'lib/constants';
  4. import { FieldArrayWithId, useFormContext, Controller } from 'react-hook-form';
  5. import { TopicConfigParams, TopicFormData } from 'redux/interfaces';
  6. import { InputLabel } from 'components/common/Input/InputLabel.styled';
  7. import { FormError } from 'components/common/Input/Input.styled';
  8. import Select from 'components/common/Select/Select';
  9. import Input from 'components/common/Input/Input';
  10. import IconButtonWrapper from 'components/common/Icons/IconButtonWrapper';
  11. import CloseIcon from 'components/common/Icons/CloseIcon';
  12. import * as C from 'components/Topics/shared/Form/TopicForm.styled';
  13. import { ConfigSource } from 'generated-sources';
  14. import * as S from './CustomParams.styled';
  15. export interface Props {
  16. config?: TopicConfigParams;
  17. isDisabled: boolean;
  18. index: number;
  19. existingFields: string[];
  20. field: FieldArrayWithId<TopicFormData, 'customParams', 'id'>;
  21. remove: (index: number) => void;
  22. setExistingFields: React.Dispatch<React.SetStateAction<string[]>>;
  23. }
  24. const CustomParamField: React.FC<Props> = ({
  25. field,
  26. isDisabled,
  27. index,
  28. remove,
  29. config,
  30. existingFields,
  31. setExistingFields,
  32. }) => {
  33. const {
  34. formState: { errors },
  35. setValue,
  36. watch,
  37. control,
  38. } = useFormContext<TopicFormData>();
  39. const nameValue = watch(`customParams.${index}.name`);
  40. const prevName = useRef(nameValue);
  41. const options = Object.keys(TOPIC_CUSTOM_PARAMS)
  42. .sort()
  43. .map((option) => ({
  44. value: option,
  45. label: option,
  46. disabled:
  47. (config &&
  48. config[option].source !== ConfigSource.DYNAMIC_TOPIC_CONFIG) ||
  49. existingFields.includes(option),
  50. }));
  51. React.useEffect(() => {
  52. if (nameValue !== prevName.current) {
  53. let newExistingFields = [...existingFields];
  54. if (prevName.current) {
  55. newExistingFields = newExistingFields.filter(
  56. (name) => name !== prevName.current
  57. );
  58. }
  59. prevName.current = nameValue;
  60. newExistingFields.push(nameValue);
  61. setExistingFields(newExistingFields);
  62. setValue(`customParams.${index}.value`, TOPIC_CUSTOM_PARAMS[nameValue], {
  63. shouldValidate: !!TOPIC_CUSTOM_PARAMS[nameValue],
  64. });
  65. }
  66. }, [existingFields, index, nameValue, setExistingFields, setValue]);
  67. return (
  68. <C.Column>
  69. <div>
  70. <InputLabel>Custom Parameter *</InputLabel>
  71. <Controller
  72. control={control}
  73. rules={{ required: 'Custom Parameter is required.' }}
  74. name={`customParams.${index}.name`}
  75. render={({ field: { value, name, onChange } }) => (
  76. <Select
  77. name={name}
  78. placeholder="Select"
  79. disabled={isDisabled}
  80. minWidth="270px"
  81. onChange={onChange}
  82. value={value}
  83. options={options}
  84. />
  85. )}
  86. />
  87. <FormError>
  88. <ErrorMessage
  89. errors={errors}
  90. name={`customParams.${index}.name` as const}
  91. />
  92. </FormError>
  93. </div>
  94. <div>
  95. <InputLabel>Value *</InputLabel>
  96. <Input
  97. name={`customParams.${index}.value` as const}
  98. hookFormOptions={{
  99. required: 'Value is required.',
  100. }}
  101. placeholder="Value"
  102. defaultValue={field.value}
  103. autoComplete="off"
  104. disabled={isDisabled}
  105. />
  106. <FormError>
  107. <ErrorMessage
  108. errors={errors}
  109. name={`customParams.${index}.value` as const}
  110. />
  111. </FormError>
  112. </div>
  113. <S.DeleteButtonWrapper>
  114. <IconButtonWrapper
  115. onClick={() => remove(index)}
  116. onKeyDown={(e: React.KeyboardEvent) =>
  117. e.code === 'Space' && remove(index)
  118. }
  119. title={`Delete customParam field ${index}`}
  120. >
  121. <CloseIcon aria-hidden />
  122. </IconButtonWrapper>
  123. </S.DeleteButtonWrapper>
  124. </C.Column>
  125. );
  126. };
  127. export default React.memo(CustomParamField);