selector.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import Field from './_field';
  2. import { View, Row } from 'app/design/view'
  3. import { useState, useMemo, useCallback } from 'react';
  4. import { Modal, NeoButton } from "app/design/controls";
  5. import ChkList from 'app/ui/molecules/form-controls/checkbox-list';
  6. import { Text } from 'app/design/typography';
  7. import { useTranslation } from 'react-i18next';
  8. import { useFormField } from 'app/lib/form/use-form-field';
  9. import { selectorInitialValue } from 'app/lib/form/field-initial-values';
  10. import { wellButtonProps } from 'app/lib/form/form-helpers';
  11. import FieldWell from './_well';
  12. export default function FormFieldSelector(props) {
  13. const { t } = useTranslation();
  14. const [isModal, setIsModal] = useState(false);
  15. const isMultiple = props.origtype == 'select' || props.is_single === true ? false : true;
  16. const defaultValue = selectorInitialValue(props?.value);
  17. const { field } = useFormField(props, {
  18. defaultValue,
  19. syncValue: false,
  20. });
  21. const [value2, setValue2] = useState(() => (Array.isArray(field.value) ? field.value : defaultValue));
  22. const variant = props.variant || 'default';
  23. const size = props.size || 'sm';
  24. const setFormValue = useCallback(
  25. (value) => {
  26. const filteredValue = value.filter(item => item);
  27. field.onChange(filteredValue);
  28. setIsModal(false);
  29. },
  30. [field]
  31. );
  32. const removeValue = useCallback(
  33. (valueToRemove) => {
  34. return () => {
  35. const newValue = field.value.filter(item => item !== valueToRemove);
  36. setValue2(newValue);
  37. field.onChange(newValue);
  38. };
  39. },
  40. [field, setValue2]
  41. );
  42. const showSelect = useCallback(
  43. () => {
  44. setValue2(Array.isArray(field.value) ? field.value : []);
  45. setIsModal(true);
  46. },
  47. [field.value]
  48. );
  49. const valuesList = useMemo(() => {
  50. return Array.isArray(props.values)
  51. ? props.values.map(obj => ({
  52. ...obj,
  53. key: obj.key !== undefined ? String(obj.key) : String(obj.value),
  54. }))
  55. : Object.entries(props.values).map(([key, value]) => ({
  56. key: String(key),
  57. value,
  58. }));
  59. }, [props.values]);
  60. const selectedItems = useMemo(() => {
  61. const selected = Array.isArray(field.value) ? field.value : [];
  62. return valuesList.filter(item => selected.includes(item.key));
  63. }, [field.value, valuesList]);
  64. const header = <Row className=' w-full justify-between items-center'>
  65. <View><NeoButton onPress={() => { setIsModal(null) }} style="glass" controlSize="regular" borderShape="circle" image="X" accessibilityLabel={t('Close')} sound="close" /></View>
  66. <View className='w-full flex-auto items-center justify-center'><Text className="text-muted-foreground text-xl font-bold">{'Choose ' + props.caption}</Text></View>
  67. <View >
  68. <NeoButton
  69. image="Check"
  70. style="glassProminent"
  71. controlSize="regular"
  72. borderShape="circle"
  73. accessibilityLabel={t('Done')}
  74. onPress={() => { setFormValue(value2) }}
  75. />
  76. </View>
  77. </Row>
  78. const ModalCnt = <Modal
  79. title={header}
  80. onVisible={isModal}
  81. onClose={() => setIsModal(false)}
  82. transparent={true}
  83. headerBorder={true}
  84. scrollable={true}
  85. skipUnsavedGuard={true}
  86. >
  87. <View className='flex-1'>
  88. <ChkList
  89. values={valuesList}
  90. selectedValue={value2}
  91. setValue={setValue2}
  92. showApply={false}
  93. multi={isMultiple}
  94. searchable={valuesList.length > 10}
  95. />
  96. </View>
  97. </Modal>
  98. const buttonProps = wellButtonProps({ variant, size });
  99. const trigger = (
  100. <NeoButton
  101. {...buttonProps}
  102. image={isMultiple ? 'Plus' : undefined}
  103. label={isMultiple ? t('Add') : selectedItems.length > 0 ? t('Change') : t('Select')}
  104. // Opens the picker dialog.
  105. sound="open"
  106. onPress={showSelect}
  107. />
  108. );
  109. return (
  110. <>
  111. {ModalCnt}
  112. <Field {...props}>
  113. <FieldWell className={props.align === 'right' ? 'justify-end' : 'justify-start'}>
  114. {props.align == 'right' && trigger}
  115. {selectedItems.map((item) => (
  116. <NeoButton
  117. key={item.key}
  118. {...buttonProps}
  119. label={item.value}
  120. image="X"
  121. imagePlacement="trailing"
  122. onPress={removeValue(item.key)}
  123. />
  124. ))}
  125. {props.align != 'right' && trigger}
  126. </FieldWell>
  127. </Field></>
  128. );
  129. }