index.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import React, { Fragment, useEffect, useRef, useState } from 'react';
  2. import { View, Text, TouchableOpacity, LayoutAnimation, Platform, UIManager, ScrollView, FlatList, StyleSheet } from 'react-native';
  3. import { PopupLayout, useLayoutAction } from '~/Components/Layouts/PopupLayout';
  4. import { SearchBoxIcon, DefaultButton, PrimaryButton } from '~/Components/Listing/Search';
  5. import { DefaultAction } from '~/Components/UIControls/Popup/Context';
  6. import { DragDrop, DragDropProvider } from '~/Components/UIControls/dragdrop';
  7. import Icon from '~/Components/UIControls/Icon';
  8. import { Util } from '~/Utils/utils';
  9. if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
  10. UIManager.setLayoutAnimationEnabledExperimental(true);
  11. }
  12. const styles = StyleSheet.create({
  13. container: {
  14. flexDirection: 'row',
  15. width: '100%',
  16. height: '100%',
  17. },
  18. destination: {
  19. backgroundColor: 'white',
  20. borderRightWidth: 1,
  21. borderColor: '#dedede',
  22. width: '50%',
  23. },
  24. destitem: {
  25. backgroundColor: '#ee4035',
  26. padding: 10,
  27. margin: 5,
  28. flexDirection: 'row',
  29. alignItems: 'center',
  30. justifyContent: 'space-between',
  31. borderRadius: 7,
  32. },
  33. destitemtext: {
  34. color: 'white',
  35. marginVertical: 5,
  36. },
  37. src: {
  38. backgroundColor: 'white',
  39. width: '50%',
  40. },
  41. srcitem: {
  42. backgroundColor: '#005b96',
  43. padding: 10,
  44. margin: 5,
  45. flexDirection: 'row',
  46. alignItems: 'center',
  47. borderRadius: 7,
  48. },
  49. srcitemtext: {
  50. color: 'white',
  51. marginVertical: 5,
  52. },
  53. });
  54. export default Popup = ({ siteId = 0, popup = DefaultAction }) => {
  55. const [items, setItems] = useState([]);
  56. const [selectItems, setSelectItems] = useState([]);
  57. const src = useRef();
  58. const dest = useRef();
  59. const destMeasure = useRef(null);
  60. const lastSelectItem = useRef();
  61. const lastSelectItemMeasure = useRef(null);
  62. const updateMeasure = async () => {
  63. destMeasure.current = await Util.getMeasure(dest.current);
  64. if (lastSelectItem.current) {
  65. lastSelectItemMeasure.current = await Util.getMeasure(lastSelectItem.current);
  66. }
  67. };
  68. const handleDraggableCheck = (e, gesture) => {
  69. if (e.nativeEvent.locationX <= 80) {
  70. src.current.setNativeProps({ scrollEnabled: false });
  71. updateMeasure();
  72. return true;
  73. } else {
  74. src.current.setNativeProps({ scrollEnabled: true });
  75. return false;
  76. }
  77. };
  78. const handleDragStart = (e, gesture) => {};
  79. const handleDragEnd = (gesture, item) => {
  80. src.current.setNativeProps({ scrollEnabled: true });
  81. if (selectItems.findIndex((value) => value.name == item.name) != -1) {
  82. return false;
  83. }
  84. if (
  85. !!destMeasure.current &&
  86. gesture.moveX >= destMeasure.current.pageX &&
  87. gesture.moveX <= destMeasure.current.pageX + destMeasure.current.width &&
  88. gesture.moveY >= destMeasure.current.pageY &&
  89. gesture.moveY <= destMeasure.current.pageY + destMeasure.current.height
  90. ) {
  91. if (selectItems.length > 0 && lastSelectItemMeasure.current) {
  92. return {
  93. dropX: lastSelectItemMeasure.current.pageX,
  94. dropY: lastSelectItemMeasure.current.pageY + lastSelectItemMeasure.current.height,
  95. };
  96. } else {
  97. return {
  98. dropX: destMeasure.current.pageX,
  99. dropY: destMeasure.current.pageY,
  100. };
  101. }
  102. }
  103. return false;
  104. };
  105. const appendSelected = (item) => {
  106. if (selectItems.findIndex((value) => value.name == item.name) != -1) return;
  107. LayoutAnimation.configureNext(LayoutAnimation.create(150, LayoutAnimation.Types.easeInEaseOut, LayoutAnimation.Properties.opacity));
  108. setSelectItems([...selectItems, { name: item.name }]);
  109. };
  110. const removeSelected = (item) => {
  111. const newItems = selectItems.filter((value) => value.name != item.name);
  112. LayoutAnimation.configureNext(LayoutAnimation.create(150, LayoutAnimation.Types.easeInEaseOut, LayoutAnimation.Properties.opacity));
  113. setSelectItems(newItems);
  114. };
  115. const actionHandler = (action, parameter = {}) => {
  116. const actions = {
  117. onClose: () => {
  118. console.log('close...');
  119. popup.close();
  120. },
  121. onSelect: () => {
  122. console.log('select...');
  123. const names = selectItems.map((item) => item.name).join(',');
  124. popup.select(names);
  125. },
  126. };
  127. actions[action]();
  128. };
  129. useEffect(() => {
  130. let list = [];
  131. for (let i = 1; i < 200; i++) {
  132. list = [...list, { id: i, name: `이름${i}` }];
  133. }
  134. setItems(list);
  135. }, []);
  136. return (
  137. <PopupLayout title="사용자 선택" header={Header} actionHandler={actionHandler}>
  138. <View style={styles.container}>
  139. <DragDropProvider>
  140. <View style={styles.destination} ref={dest}>
  141. <ScrollView style={{ width: '100%', height: '100%' }}>
  142. {selectItems.map((item, index) => {
  143. const last = selectItems.length - 1 == index;
  144. return (
  145. <View key={`select-item-${index}`} style={styles.destitem} ref={last ? lastSelectItem : undefined}>
  146. <Text style={styles.destitemtext}>{item.name}</Text>
  147. <TouchableOpacity onPress={() => removeSelected(item)}>
  148. <Icon iconFamily="AntDesign" iconName="minuscircle" size={20} color="white" />
  149. </TouchableOpacity>
  150. </View>
  151. );
  152. })}
  153. </ScrollView>
  154. </View>
  155. <FlatList
  156. style={[styles.src, { overflow: 'visible' }]}
  157. ref={src}
  158. data={items}
  159. keyExtractor={(item, index) => `item-${index}`}
  160. renderItem={({ item, index }) => {
  161. return (
  162. <DragDrop
  163. style={styles.srcitem}
  164. onDraggableCheck={handleDraggableCheck}
  165. onDragStart={handleDragStart}
  166. onDragEnd={(gesture) => {
  167. return handleDragEnd(gesture, item);
  168. }}
  169. hideWhenDrop={true}
  170. onRemove={() => {
  171. appendSelected(item);
  172. }}
  173. >
  174. <Icon iconFamily="MaterialCommunityIcons" iconName="drag" size={20} color="white" />
  175. <Text style={styles.srcitemtext}>{item.name}</Text>
  176. </DragDrop>
  177. );
  178. }}
  179. />
  180. </DragDropProvider>
  181. </View>
  182. </PopupLayout>
  183. );
  184. };
  185. const Header = () => {
  186. const { callAction } = useLayoutAction();
  187. return (
  188. <Fragment>
  189. <DefaultButton
  190. onPress={() => {
  191. callAction('onClose');
  192. }}
  193. >
  194. 닫기
  195. </DefaultButton>
  196. <PrimaryButton
  197. onPress={() => {
  198. callAction('onSelect');
  199. }}
  200. >
  201. 선택
  202. </PrimaryButton>
  203. </Fragment>
  204. );
  205. };