index.tsx 5.4 KB

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