index.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import React, { useEffect, useState } from 'react';
  2. import { View, Platform, SafeAreaView, Text, TouchableOpacity } from 'react-native';
  3. import MapView, { Geojson, UrlTile } from 'react-native-maps';
  4. import kye from '../../../../../assets/geojson/kye.json';
  5. import { Header } from 'src/components';
  6. import { useGetKyeQuery, usePostSetKye } from '@api/travels';
  7. import { StoreType, storage } from 'src/storage';
  8. import { FeatureCollection } from '@turf/turf';
  9. import { FASTEST_MAP_HOST } from 'src/constants';
  10. import { styles } from './styles';
  11. import InfoIcon from 'assets/icons/info-solid.svg';
  12. import { NAVIGATION_PAGES } from 'src/types';
  13. import { useNavigation } from '@react-navigation/native';
  14. interface PropertiesData {
  15. id: number;
  16. tt: string;
  17. mega: string;
  18. name: string;
  19. fill?: string;
  20. }
  21. const EarthScreen = () => {
  22. const token = storage.get('token', StoreType.STRING) as string || '';
  23. const [geojson, setGeojson] = useState<FeatureCollection>(kye as FeatureCollection);
  24. const { data } = useGetKyeQuery(token, true);
  25. const { mutateAsync } = usePostSetKye();
  26. const [visited, setVisited] = useState<number[]>([]);
  27. const [score, setScore] = useState({ base: 0, percentage: 0 });
  28. const [quadrantsAll, setQuadrantsAll] = useState<number>(1);
  29. const navigation = useNavigation();
  30. useEffect(() => {
  31. if (!data || !data.regions) return;
  32. setQuadrantsAll(data.regions?.length);
  33. token && setVisited(data.visited);
  34. }, [data]);
  35. useEffect(() => {
  36. const updatedGeojson = updateGeojsonStyles(geojson);
  37. setGeojson(updatedGeojson);
  38. showScore();
  39. }, [visited]);
  40. const getFeatureStyle = (properties: PropertiesData) => {
  41. const style = {
  42. fill: 'transparent'
  43. };
  44. if (properties.tt == '1') {
  45. if (properties.id > 612) {
  46. if (Math.max(...visited) > 612) {
  47. style.fill = 'rgba(132, 138, 68, 0.5)';
  48. } else {
  49. style.fill = 'rgba(21, 99, 123, 0.5)';
  50. }
  51. } else {
  52. if (visited.includes(properties.id)) {
  53. style.fill = 'rgba(132, 138, 68, 0.5)';
  54. } else {
  55. style.fill = 'rgba(21, 99, 123, 0.5)';
  56. }
  57. }
  58. } else {
  59. style.fill = 'rgba(230, 230, 230, 0.5)';
  60. }
  61. return style;
  62. };
  63. const updateGeojsonStyles = (geojson: FeatureCollection) => {
  64. const updatedFeatures = geojson.features.map((feature) => {
  65. const style = getFeatureStyle(feature.properties as PropertiesData);
  66. return { ...feature, properties: { ...feature.properties, ...style } };
  67. });
  68. return { ...geojson, features: updatedFeatures };
  69. };
  70. const markQuadrant = async (qid: number) => {
  71. if (!token) return;
  72. let vis: 0 | 1 = 1;
  73. if (qid > 612) {
  74. if (Math.max(...visited) > 612) {
  75. vis = 0;
  76. }
  77. } else {
  78. if (visited.includes(qid)) {
  79. vis = 0;
  80. }
  81. }
  82. try {
  83. await mutateAsync(
  84. { token, qid, visited: vis },
  85. {
  86. onSuccess: () => {
  87. if (vis == 0) {
  88. quadRemove(qid);
  89. } else {
  90. quadAdd(qid);
  91. }
  92. }
  93. }
  94. );
  95. } catch (error) {
  96. console.error('Failed to update kye state', error);
  97. }
  98. };
  99. const quadAdd = (qid: number) => {
  100. setVisited((prevVisited) => {
  101. if (qid > 612) {
  102. const newVisited = [...prevVisited];
  103. for (let i = 613; i < 649; i++) {
  104. if (!newVisited.includes(i)) {
  105. newVisited.push(i);
  106. }
  107. }
  108. return newVisited;
  109. } else {
  110. if (!prevVisited.includes(qid)) {
  111. return [...prevVisited, qid];
  112. }
  113. return prevVisited;
  114. }
  115. });
  116. };
  117. const quadRemove = (qid: number) => {
  118. setVisited((prevVisited) => {
  119. if (qid > 612) {
  120. return prevVisited.filter((id) => id < 613 || id > 648);
  121. } else {
  122. return prevVisited.filter((id) => id !== qid);
  123. }
  124. });
  125. };
  126. const showScore = () => {
  127. let baseList = visited.filter((id) => id < 613);
  128. let score = baseList.length;
  129. if (Math.max(...visited) > 612) {
  130. score += 1;
  131. }
  132. let calc = Math.round((score / quadrantsAll) * 10000) / 100;
  133. setScore({ base: score, percentage: calc });
  134. };
  135. return (
  136. <SafeAreaView style={{ height: '100%' }}>
  137. <View style={styles.wrapper}>
  138. <Header
  139. label={'My Earth'}
  140. // rightElement={
  141. // <TouchableOpacity
  142. // onPress={() => navigation.navigate(NAVIGATION_PAGES.EARTH_INFO as never)}
  143. // style={{ width: 30 }}
  144. // >
  145. // <InfoIcon />
  146. // </TouchableOpacity>
  147. // }
  148. />
  149. {token && (
  150. <View style={styles.score}>
  151. <Text style={[styles.scoreText, { fontWeight: 'bold' }]}>Your score: {score.base}</Text>
  152. <Text style={[styles.scoreText, { fontSize: 14 }]}>{`(${score.percentage}%)`}</Text>
  153. </View>
  154. )}
  155. </View>
  156. <View style={styles.container}>
  157. <MapView
  158. style={styles.map}
  159. showsMyLocationButton={false}
  160. showsCompass={false}
  161. zoomControlEnabled={false}
  162. mapType={Platform.OS == 'android' ? 'none' : 'standard'}
  163. maxZoomLevel={15}
  164. minZoomLevel={0}
  165. initialRegion={{
  166. latitude: 0,
  167. longitude: 0,
  168. latitudeDelta: 180,
  169. longitudeDelta: 180
  170. }}
  171. >
  172. <UrlTile
  173. urlTemplate={`${FASTEST_MAP_HOST}/tiles_osm/{z}/{x}/{y}`}
  174. maximumZ={15}
  175. maximumNativeZ={13}
  176. shouldReplaceMapContent
  177. minimumZ={0}
  178. />
  179. <Geojson
  180. geojson={geojson as any}
  181. zIndex={1}
  182. tappable={true}
  183. onPress={(event) => {
  184. markQuadrant(event.feature.properties?.id);
  185. }}
  186. tracksViewChanges={false}
  187. />
  188. </MapView>
  189. </View>
  190. </SafeAreaView>
  191. );
  192. };
  193. export default EarthScreen;