LandmarkForm.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { ScrollView, View, Text, StyleSheet, TouchableOpacity, Dimensions, Image, Alert} from 'react-native';
  3. import { TextInput } from 'react-native-paper';
  4. import { Controller, useForm } from 'react-hook-form';
  5. import { useMockState } from '../contexts/MockContext';
  6. import Modal from 'react-native-modalbox';
  7. import { Icons } from '../globals';
  8. import Icon from 'react-native-vector-icons/FontAwesome';
  9. import { v4 as uuidv4 } from 'uuid';
  10. const editTheme = {
  11. colors: {
  12. primary: 'black',
  13. text: 'black'
  14. }
  15. }
  16. const LandmarkForm = ({navigation}) => {
  17. const {dispatch, state} = useMockState();
  18. const { control, isDirty, handleSubmit, setValue, formState } = useForm({
  19. mode: 'all'
  20. });
  21. const [selectedIcon, setIcon] = useState(state.selectedLandmark.icon);
  22. const iconSelector = useRef();
  23. useEffect(() => {
  24. setValue('title', state.selectedLandmark.title);
  25. setValue('desc', state.selectedLandmark.desc);
  26. setIcon(state.selectedLandmark.icon)
  27. }, [state]);
  28. const saveLandmark = (formData) => {
  29. let currentLandmark = state.landmarks.filter(l => l.id === state.selectedLandmark.id)[0];
  30. console.log(currentLandmark)
  31. if (currentLandmark != null) {
  32. // we're updating an existing landmark
  33. dispatch({type: "UPDATE_LANDMARKS", payload: state.landmarks.map(l => {
  34. if (l.id === state.selectedLandmark.id) {
  35. currentLandmark = {...l, title: formData.title, desc: formData.desc, icon: selectedIcon};
  36. dispatch({type: "UPDATE_SELECTED_LANDMARK", payload: currentLandmark});
  37. return currentLandmark;
  38. }
  39. return l;
  40. })});
  41. console.log('here')
  42. navigation.navigate('Map');
  43. }
  44. else {
  45. // we're adding a new landmark
  46. const newLandmark = {
  47. id: uuidv4(),
  48. postedBy: 'cdmoss',
  49. dateAdded: Date.now(),
  50. title: formData.title,
  51. desc: formData.desc,
  52. icon: selectedIcon,
  53. longitude: state.selectedLandmark.longitude,
  54. latitude: state.selectedLandmark.latitude,
  55. comments: []
  56. };
  57. dispatch({type: "UPDATE_LANDMARKS", payload: [...state.landmarks, newLandmark]})
  58. navigation.navigate('Map');
  59. }
  60. }
  61. const openSelector = () => {
  62. iconSelector.current.open();
  63. }
  64. const updateIcon = (icon) => {
  65. setIcon(icon);
  66. iconSelector.current.close();
  67. }
  68. const closeModal = () => {
  69. iconSelector.current.close();
  70. }
  71. return (
  72. <View style={styles.container}>
  73. <View style={styles.inputContainer}>
  74. <ScrollView>
  75. <Controller
  76. control={control}
  77. render={({ field: { onBlur, onChange, value }}) => (
  78. <TextInput
  79. multiline={true}
  80. theme={editTheme}
  81. underlineColor="white"
  82. style={[styles.title, styles.input]}
  83. placeholder="Title"
  84. value={value}
  85. onBlur={value => onBlur(value)}
  86. onChangeText={value => onChange(value)}
  87. ></TextInput>
  88. )}
  89. name="title"
  90. rules={{ required: true, maxLength: 100 }} />
  91. {formState.errors.title?.type === "required" && <Text style={styles.errorText}>Title is required.</Text>}
  92. <Controller
  93. control={control}
  94. render={({ field: { onChange, onBlur, value }}) => (
  95. <TextInput
  96. multiline={true}
  97. theme={editTheme}
  98. style={[styles.desc, styles.input]}
  99. placeholder="Description"
  100. value={value}
  101. on={value => onBlur(value)}
  102. onChangeText={value => onChange(value)}
  103. ></TextInput>
  104. )}
  105. name="desc"
  106. rules={{ required: true, maxLength: 500 }} />
  107. {formState.errors.desc?.type === "required" && <Text style={styles.errorText}>Description is required.</Text>}
  108. {formState.errors.desc?.type === "maxLength" && <Text style={styles.errorText}>Description must be less than 500 characters.</Text>}
  109. <Text style={styles.label}>Type</Text>
  110. <TouchableOpacity onPress={openSelector}>
  111. <View style={styles.selectedIconContainer}>
  112. <View style={styles.selectedIcon}>
  113. <Image style={{height: 30, width: 22}} source={Icons[selectedIcon]}/>
  114. <Text style={{marginLeft: 15, color: 'black'}}>{selectedIcon}</Text>
  115. </View>
  116. <Icon style={iconSelector.isOpen ? { transform: [{rotate: '180deg'}] } : null} name="chevron-down" />
  117. </View>
  118. </TouchableOpacity>
  119. </ScrollView>
  120. </View>
  121. <TouchableOpacity style={{margin: 20, alignSelf: 'flex-end', zIndex: 5}} onPress={handleSubmit(saveLandmark)}>
  122. <Text style={{fontSize: 15, color: 'white'}}>Save Changes</Text>
  123. </TouchableOpacity>
  124. <Modal position={"bottom"} ref={iconSelector} style={{height: 400}} >
  125. <TouchableOpacity
  126. style={{flexDirection: 'row', justifyContent: 'center', paddingVertical: 10}}
  127. onPress={closeModal}>
  128. <Icon name="chevron-down"/>
  129. </TouchableOpacity>
  130. <ScrollView style={{marginBottom: 100}}>
  131. {Object.entries(Icons).map(icon => {
  132. return(
  133. <TouchableOpacity style={styles.iconChoice} key={icon[0]} onPress={() => updateIcon(icon[0])} >
  134. <Image style={{height: 30, width: 22}} source={icon[1]}/>
  135. <Text style={{marginLeft: 15}}>{icon[0]}</Text>
  136. </TouchableOpacity>)
  137. })}
  138. </ScrollView>
  139. </Modal>
  140. </View>
  141. )
  142. }
  143. const styles = StyleSheet.create({
  144. container: {
  145. position: 'absolute',
  146. width: Dimensions.get('window').width,
  147. height: Dimensions.get('window').height,
  148. flex: 1,
  149. backgroundColor: '#df3f3f',
  150. },
  151. inputContainer: {
  152. height: 500,
  153. paddingHorizontal: 20,
  154. paddingBottom: 20,
  155. paddingTop: 70,
  156. },
  157. label: {
  158. color: 'white',
  159. marginTop: 20,
  160. marginBottom: 8
  161. },
  162. title: {
  163. fontSize: 20,
  164. marginBottom: 20,
  165. },
  166. input: {
  167. backgroundColor: 'white',
  168. },
  169. desc: {
  170. color: 'white',
  171. },
  172. iconPicker: {
  173. color: 'white',
  174. },
  175. selectedIconContainer: {
  176. backgroundColor: 'white',
  177. paddingHorizontal: 30,
  178. padding: 15,
  179. flexDirection: 'row',
  180. alignItems: 'center',
  181. justifyContent: 'space-between'
  182. },
  183. errorText: {
  184. alignSelf: 'flex-end',
  185. color: 'black',
  186. fontSize: 15
  187. },
  188. selectedIcon: {
  189. backgroundColor: 'white',
  190. flexDirection: 'row',
  191. alignItems: 'center',
  192. },
  193. iconChoice: {
  194. marginHorizontal: 30,
  195. paddingVertical: 10,
  196. flexDirection: 'row',
  197. alignItems: 'center',
  198. borderBottomWidth: 1,
  199. },
  200. chevronRotate: {
  201. transform: [{ rotate: '180deg'}]
  202. }
  203. })
  204. export default LandmarkForm;