src_components_LandmarkDetails.tsx.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title> src/components/LandmarkDetails.tsx</title>
  7. <script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script>
  8. <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  9. <script src="./build/entry.js"></script>
  10. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  11. <!--[if lt IE 9]>
  12. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  13. <![endif]-->
  14. <link href="https://fonts.googleapis.com/css?family=Roboto:100,400,700|Inconsolata,700" rel="stylesheet">
  15. <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
  16. <link type="text/css" rel="stylesheet" href="https://jmblog.github.io/color-themes-for-google-code-prettify/themes/tomorrow-night.min.css">
  17. <link type="text/css" rel="stylesheet" href="styles/app.min.css">
  18. <link type="text/css" rel="stylesheet" href="styles/iframe.css">
  19. <link type="text/css" rel="stylesheet" href="">
  20. <script async defer src="https://buttons.github.io/buttons.js"></script>
  21. </head>
  22. <body class="layout small-header">
  23. <div id="stickyNavbarOverlay"></div>
  24. <div class="top-nav">
  25. <div class="inner">
  26. <a id="hamburger" role="button" class="navbar-burger" aria-label="menu" aria-expanded="false">
  27. <span aria-hidden="true"></span>
  28. <span aria-hidden="true"></span>
  29. <span aria-hidden="true"></span>
  30. </a>
  31. <div class="logo">
  32. </div>
  33. <div class="menu">
  34. <div class="navigation">
  35. <a
  36. href="index.html"
  37. class="link"
  38. >
  39. API Documentation
  40. </a>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. <div id="main">
  46. <div
  47. class="sidebar "
  48. id="sidebarNav"
  49. >
  50. <nav>
  51. <h2><a href="index.html">Documentation</a></h2><div class="category"><h3>Interfaces</h3><ul><li><a href="AddLandmarkProps.html">AddLandmarkProps</a></li><li><a href="CommentProps.html">CommentProps</a></li><li><a href="IdToken.html">IdToken</a></li><li><a href="IntroProps.html">IntroProps</a></li><li><a href="Landmark.html">Landmark</a></li><li><a href="LandmarkDetailsProps.html">LandmarkDetailsProps</a></li><li><a href="LandmarkPinProps.html">LandmarkPinProps</a></li><li><a href="LMComment.html">LMComment</a></li><li><a href="ProfileProps.html">ProfileProps</a></li><li><a href="RegisterProps.html">RegisterProps</a></li><li><a href="UserProfile.html">UserProfile</a></li></ul><h3>Components</h3><ul><li><a href="App.html">App</a></li><li><a href="Atlas.html">Atlas</a></li><li><a href="Comment.html">Comment</a></li><li><a href="PrimaryButton.html">PrimaryButton</a></li><li><a href="Profile.html">Profile</a></li><li><a href="SecondaryButton.html">SecondaryButton</a></li></ul><h3>Global</h3><ul><li><a href="global.html#IconStrings">IconStrings</a></li></ul></div><div class="category"><h2>Hooks</h2><h3>Namespaces</h3><ul><li><a href="useAuth.html">useAuth</a></li><li><a href="useLandmarks.html">useLandmarks</a></li><li><a href="useProfile.html">useProfile</a></li></ul></div><div class="category"><h2>Map</h2><h3>Interfaces</h3><ul><li><a href="UserLocation.html">UserLocation</a></li></ul><h3>Components</h3><ul><li><a href="AddLandmark.html">AddLandmark</a></li><li><a href="LandmarkDetails.html">LandmarkDetails</a></li><li><a href="LandmarkPin.html">LandmarkPin</a></li><li><a href="Map.html">Map</a></li></ul></div><div class="category"><h2>Navigation</h2><h3>Components</h3><ul><li><a href="AuthorizedNavigator.html">AuthorizedNavigator</a></li><li><a href="UnauthorizedNavigator.html">UnauthorizedNavigator</a></li></ul><h3><a href="global.html">Global</a></h3></div><div class="category"><h2>Stores</h2><h3>Classes</h3><ul><li><a href="AuthStore.html">AuthStore</a></li></ul></div><div class="category"><h2>Unauthorized</h2><h3>Components</h3><ul><li><a href="Intro.html">Intro</a></li><li><a href="UnauthorizedLayout.html">UnauthorizedLayout</a></li></ul><h3>Components / Registration</h3><ul><li><a href="RegisterMain.html">RegisterMain</a></li></ul></div>
  52. </nav>
  53. </div>
  54. <div class="core" id="main-content-wrapper">
  55. <div class="content">
  56. <header class="page-title">
  57. <p>Source</p>
  58. <h1>src/components/LandmarkDetails.tsx</h1>
  59. </header>
  60. <section>
  61. <article>
  62. <pre class="prettyprint source linenums"><code>import { FontAwesome } from "@expo/vector-icons";
  63. import React, { memo, useCallback, useEffect, useRef, useState } from "react";
  64. import { ActivityIndicator, Dimensions, Image, Keyboard, ListRenderItem, StyleSheet, Text, TextInput, View } from "react-native";
  65. import { ScrollView, TouchableWithoutFeedback } from "react-native-gesture-handler";
  66. import Picker from "react-native-picker-select";
  67. import { colors, Icons, IconStrings } from "../globals";
  68. import { Landmark, LMComment, useLandmarks } from "../hooks/useLandmarks";
  69. import { authStore } from "../stores/AuthStore";
  70. import { PrimaryButton } from "./Auth/Buttons";
  71. /**
  72. * Props for the {@link Comment} component.
  73. */
  74. export interface CommentProps {
  75. /**
  76. * The [comment]{@link LMComment} object being displayed by the {@link Comment} component.
  77. */
  78. comment: LMComment
  79. }
  80. /**
  81. * Component that displays a {@link LMComment} object in a clean format.
  82. * @component
  83. */
  84. export const Comment: React.FC&lt;CommentProps> = ({comment}) => (
  85. &lt;View>
  86. &lt;Text testID="comment-text">{comment.text}&lt;/Text>
  87. &lt;/View>
  88. )
  89. /**
  90. * Props for the {@link LandmarkDetails} component.
  91. */
  92. export interface LandmarkDetailsProps {
  93. /**
  94. * The {@link Landmark} object being displayed/edited in the {@link LandmarkDetails} modal.
  95. */
  96. landmark: Landmark | undefined
  97. /**
  98. * A callback passed from the parent {@link Map} that toggles the visibility of the {@link LandmarkDetails} modal.
  99. */
  100. setVisible: (state: boolean) => void;
  101. /**
  102. * A callback passed from the parent {@link Map} that toggles the ability to edit the {@link Landmark} in {@link LandmarkDetails} modal.
  103. */
  104. setEditing: (state: boolean) => void;
  105. /**
  106. * A flag that determines whether the properties of the {@link Landmark} displayed in the {@link LandmarkDetails} modal can be edited
  107. */
  108. editingEnabled: boolean
  109. }
  110. /**
  111. * Component that renders the details of a selected {@link Landmark} and allows the user to edit those details. Contained within a [react-native-modal]{@link https://github.com/react-native-modal/react-native-modal}.
  112. * @component
  113. * @category Map
  114. */
  115. const LandmarkDetails: React.FC&lt;LandmarkDetailsProps> = ({landmark, setVisible, setEditing, editingEnabled}) => {
  116. /**
  117. * Holds the state of the {@link Landmark} being displayed.
  118. */
  119. const selectedLandmarkState = undefined;
  120. const [selectedLandmark, setLandmark] = useState&lt;Landmark | undefined>(selectedLandmarkState);
  121. /**
  122. * Holds state of a {@link Landmark} object parallel to {@linkcode selectedLandmarkState} that is manipulated when {@linkcode editingEnabled} is true.
  123. */
  124. const updatedLandmarkState = undefined;
  125. const [updatedLandmark, setUpdatedLandmark] = useState&lt;Landmark | undefined>(updatedLandmarkState);
  126. const {
  127. updateLandmark, updateLandmarkStatus, resetUpdateLm,
  128. deleteLandmark, deleteLandmarkStatus, resetDeleteLm,
  129. } = useLandmarks(undefined);
  130. useEffect(() => {
  131. /**
  132. * Updates this component's {@linkcode selectedLandmarkState} when the {@linkcode landmark} prop passed down from the parent {@link Map}'s {@linkcode selectedLandmark} is changed.
  133. * Embedded in a useEffect that listens to the {@linkcode landmark} prop.
  134. * @memberOf LandmarkDetails
  135. */
  136. const updateLandmarkStateFromParent = () => {
  137. setLandmark(landmark)
  138. };
  139. updateLandmarkStateFromParent();
  140. }, [landmark])
  141. useEffect(() => {
  142. /**
  143. * Resets the {@linkcode updateLandmark} mutation on successful add.
  144. * Embedded in a useEffect that listens to the {@linkcode updateLandmarkStatus} value from the {@link useLandmarks} hook.
  145. * @memberOf LandmarkDetails
  146. */
  147. const resetUpdateMutationOnSuccess = () => {
  148. if (updateLandmarkStatus == 'success') {
  149. resetUpdateLm();
  150. setLandmark(updatedLandmark)
  151. }
  152. }
  153. resetUpdateMutationOnSuccess();
  154. }, [updateLandmarkStatus]);
  155. useEffect(() => {
  156. /**
  157. * Resets the {@linkcode deleteLandmark} mutation on successful delete.
  158. * Embedded in a useEffect that listens to the {@linkcode deleteLandmarkStatus} value from the {@link useLandmarks} hook.
  159. * @memberOf LandmarkDetails
  160. */
  161. const resetDeleteMutationOnSuccess = () => {
  162. if (deleteLandmarkStatus == 'success') {
  163. resetDeleteLm();
  164. }
  165. }
  166. resetDeleteMutationOnSuccess();
  167. }, [deleteLandmarkStatus]);
  168. /**
  169. * Toggles whether or not the {@linkcode selectedLandmark} can be edited through the {@linkcode editingEnabled} prop.
  170. */
  171. const toggleEditing = (editingState: boolean) => {
  172. if (editingState) { setUpdatedLandmark(selectedLandmark); }
  173. else { setUpdatedLandmark(undefined); }
  174. setEditing(editingState);
  175. }
  176. /**
  177. * Calls the {@linkcode updateLandmark} mutation from the {@link useLandmarks} hook and closes the modal once finished.
  178. */
  179. const editLandmark = async () => {
  180. if (updatedLandmark) {
  181. await updateLandmark(updatedLandmark);
  182. }
  183. setEditing(false);
  184. }
  185. /**
  186. * Calls the {@linkcode deleteLandmark} mutation from the {@link useLandmarks} hook and closes the modal once finished.
  187. */
  188. const removeLandmark = async () => {
  189. await deleteLandmark(selectedLandmark?.id);
  190. setVisible(false);
  191. }
  192. /**
  193. * Renders all [comments]{@link LMComment} associated with the {@linkcode selectedLandmark} as items for the [FlatList]{@link https://reactnative.dev/docs/flatlist} in this component.
  194. */
  195. const renderComment: ListRenderItem&lt;LMComment> = useCallback(({item}) => (
  196. &lt;Comment comment={item} />
  197. ), []);
  198. return (
  199. &lt;View style={[styles.container, editingEnabled ? {height: Dimensions.get("window").height * .4,} : {height: Dimensions.get("window").height * .4,}]}>
  200. {updateLandmarkStatus == "idle" &amp;&amp; deleteLandmarkStatus == "idle" ?
  201. &lt;>
  202. &lt;View style={styles.detailsHeader}>
  203. {authStore.userId !== selectedLandmark?.user ? null : !editingEnabled ?
  204. &lt;View style={{flexDirection: 'row', alignItems: "center"}}>
  205. &lt;FontAwesome style={{marginRight: 20, marginTop: 2}} size={25} color="white" name="edit" onPress={() => toggleEditing(true)}/>
  206. &lt;FontAwesome color="white" size={25} name="trash" onPress={async () => removeLandmark()}/>
  207. &lt;/View> :
  208. &lt;View style={{flexDirection: 'row', alignItems: "center",}}>
  209. &lt;FontAwesome color="white" size={25} name="close" onPress={() => toggleEditing(false)}/>
  210. &lt;/View>}
  211. {!editingEnabled ?
  212. &lt;FontAwesome color="white" size={25} name="close" onPress={() => setVisible(false)}/>:
  213. updatedLandmark?.description &amp;&amp; updatedLandmark.landmark_type ?
  214. &lt;FontAwesome style={{marginTop: 2}} size={25} color="white" name="check" onPress={async () => editLandmark()}/> : null}
  215. &lt;/View>
  216. &lt;View style={styles.detailsContainer}>
  217. {editingEnabled ?
  218. &lt;View>
  219. &lt;View style={{flexDirection: 'row', marginBottom: 20, justifyContent: "space-between"}}>
  220. {updatedLandmark?.landmark_type ?
  221. &lt;>
  222. &lt;Picker
  223. style={{
  224. inputIOS: {color: 'white'},
  225. inputAndroid: {color: 'white'},
  226. viewContainer: {marginVertical: 10, flex: 1}, placeholder: {color: 'white'}}}
  227. textInputProps={{placeholderTextColor: 'white', selectionColor: 'white'}}
  228. Icon={() => &lt;FontAwesome name="chevron-down" color='white' size={20} />}
  229. placeholder={
  230. selectedLandmark?.landmark_type ?
  231. {label: IconStrings[selectedLandmark.landmark_type].toUpperCase(), value: selectedLandmark.landmark_type} :
  232. {label: "Select landmark type", value: 0} }
  233. value={updatedLandmark.landmark_type}
  234. onValueChange={(value) => {
  235. setUpdatedLandmark({...updatedLandmark, landmark_type: value, title: IconStrings[value]})
  236. }}
  237. useNativeAndroidPickerStyle={true}
  238. items={Object.keys(Icons)?.filter(icon => parseInt(icon) != selectedLandmark?.landmark_type).map(icon => {
  239. return (
  240. {label: IconStrings[parseInt(icon)].toUpperCase(), value: icon, key: icon}
  241. )})}
  242. />
  243. &lt;Image style={{marginLeft: 20}} source={Icons[updatedLandmark.landmark_type]}/>
  244. &lt;/>
  245. : null}
  246. &lt;/View>
  247. &lt;TouchableWithoutFeedback style={{marginBottom: 20}} onPress={() => Keyboard.dismiss()}>
  248. &lt;ScrollView style={{backgroundColor: 'white'}}>
  249. &lt;TextInput
  250. multiline={true}
  251. style={[styles.input, {fontSize: 13, marginBottom: 10}]}
  252. onChangeText={(value) => setUpdatedLandmark({...updatedLandmark, description: value})} >
  253. {updatedLandmark?.description}
  254. &lt;/TextInput>
  255. &lt;/ScrollView>
  256. &lt;/TouchableWithoutFeedback>
  257. &lt;/View>:
  258. &lt;View style={{flexDirection: 'row'}}>
  259. &lt;View style={{flex: 8, flexDirection: 'column', marginBottom: 20}}>
  260. &lt;Text style={{color: 'white', marginBottom: 10, fontSize: 15}}>{selectedLandmark?.title?.toUpperCase()}&lt;/Text>
  261. &lt;ScrollView>
  262. &lt;Text style={{color: 'white', fontSize: 13}}>{selectedLandmark?.description}&lt;/Text>
  263. &lt;/ScrollView>
  264. &lt;/View>
  265. {selectedLandmark?.landmark_type ? &lt;Image source={Icons[selectedLandmark.landmark_type]} /> : null}
  266. &lt;/View>}
  267. &lt;TouchableWithoutFeedback style={{height: '100%'}} onPress={() => Keyboard.dismiss()}>&lt;Text>&lt;/Text>&lt;/TouchableWithoutFeedback>
  268. {/* {!editingEnabled ?
  269. &lt;View style={styles.commentContainer}>
  270. &lt;Text style={{color: 'white', marginBottom: 20}}>Comments: &lt;/Text>
  271. &lt;FlatList&lt;LMComment>
  272. keyExtractor={i => i.id}
  273. data={[
  274. {id: '1', text: 'Hello', poster: 'chase'}, {id: '3', text: 'Hello', poster: 'chase'}, {id: '2', text: 'Hello', poster: 'chase'},
  275. {id: '4', text: 'Hello', poster: 'chase'}, {id: '5', text: 'Hello', poster: 'chase'}, {id: '6', text: 'Hello', poster: 'chase'},
  276. {id: '9', text: 'Hello', poster: 'chase'}, {id: '8', text: 'Hello', poster: 'chase'}, {id: '7', text: 'Hello', poster: 'chase'},
  277. {id: '12', text: 'Hello', poster: 'chase'}, {id: '10', text: 'Hello', poster: 'chase'}, {id: '11', text: 'Hello', poster: 'chase'},
  278. ]}
  279. renderItem={renderComment}
  280. style={{backgroundColor: 'white'}}/>
  281. &lt;/View> : null} */}
  282. &lt;/View>
  283. &lt;/> :
  284. &lt;View style={{height: '100%', justifyContent: "space-evenly", alignItems: "center", marginHorizontal: 20}}>
  285. &lt;Text style={{color: 'white', fontSize: 20}}>{
  286. deleteLandmarkStatus == 'loading' ? "Deleting landmark..." :
  287. deleteLandmarkStatus == 'error' ? "Something went wrong trying to delete the landmark" :
  288. updateLandmarkStatus == 'loading' ? "Updating landmark..." :
  289. updateLandmarkStatus == 'error' ? "Something went wrong trying to update the landmark" : null}
  290. &lt;/Text>
  291. {
  292. deleteLandmarkStatus == 'loading' || updateLandmarkStatus == 'loading' ? &lt;ActivityIndicator color='white' size="large"/> :
  293. deleteLandmarkStatus == 'error' || updateLandmarkStatus == 'error' ? &lt;PrimaryButton text="Okay" style={{borderColor: 'white', borderWidth: 1}} onPress={() => setVisible(false)} /> : null
  294. }
  295. &lt;/View> }
  296. &lt;/View>
  297. )
  298. }
  299. const styles = StyleSheet.create({
  300. container: {
  301. backgroundColor: colors.red,
  302. },
  303. detailsHeader: {
  304. borderBottomWidth: 1,
  305. borderColor: 'white',
  306. flexDirection: 'row',
  307. justifyContent: 'space-between',
  308. alignItems: 'center',
  309. backgroundColor: '#df3f3f',
  310. marginBottom: 10,
  311. paddingVertical: 10,
  312. paddingHorizontal: 20
  313. },
  314. detailsContainer: {
  315. flex: 1,
  316. marginHorizontal: 20
  317. },
  318. commentContainer: {
  319. flex: 5,
  320. marginBottom: 40
  321. },
  322. title: {
  323. },
  324. input: {
  325. padding: 5,
  326. color: 'black'
  327. }
  328. })
  329. export default memo(LandmarkDetails);</code></pre>
  330. </article>
  331. </section>
  332. </div>
  333. <footer class="footer">
  334. <div class="content has-text-centered">
  335. <p>Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.7</a></p>
  336. <p class="sidebar-created-by">
  337. <a href="https://github.com/SoftwareBrothers/better-docs" target="_blank">BetterDocs theme</a> provided with <i class="fas fa-heart"></i> by
  338. <a href="http://softwarebrothers.co" target="_blank">SoftwareBrothers - JavaScript Development Agency</a>
  339. </p>
  340. </div>
  341. </footer>
  342. </div>
  343. <div id="side-nav" class="side-nav">
  344. </div>
  345. </div>
  346. <script src="scripts/app.min.js"></script>
  347. <script>PR.prettyPrint();</script>
  348. <script src="scripts/linenumber.js"> </script>
  349. </body>
  350. </html>