|
@@ -0,0 +1,195 @@
|
|
|
+import React, { useEffect, useState } from 'react';
|
|
|
+import { View, Platform, SafeAreaView, Text } from 'react-native';
|
|
|
+import MapView, { Geojson, UrlTile } from 'react-native-maps';
|
|
|
+
|
|
|
+import kye from '../../../../../assets/geojson/kye.json';
|
|
|
+import { Header } from 'src/components';
|
|
|
+import { useGetKyeQuery, usePostSetKye } from '@api/travels';
|
|
|
+import { StoreType, storage } from 'src/storage';
|
|
|
+
|
|
|
+import { FeatureCollection } from '@turf/turf';
|
|
|
+import { MAP_HOST } from 'src/constants';
|
|
|
+import { styles } from './styles';
|
|
|
+
|
|
|
+interface PropertiesData {
|
|
|
+ id: number;
|
|
|
+ tt: string;
|
|
|
+ mega: string;
|
|
|
+ name: string;
|
|
|
+ fill?: string;
|
|
|
+}
|
|
|
+
|
|
|
+const EarthScreen = () => {
|
|
|
+ const token = storage.get('token', StoreType.STRING) as string;
|
|
|
+ const [geojson, setGeojson] = useState<FeatureCollection>(kye as FeatureCollection);
|
|
|
+ const { data } = useGetKyeQuery(token, true);
|
|
|
+ const { mutateAsync } = usePostSetKye();
|
|
|
+ const [visited, setVisited] = useState<number[]>([]);
|
|
|
+ const [score, setScore] = useState({ base: 0, percentage: 0 });
|
|
|
+ const [quadrantsAll, setQuadrantsAll] = useState<number>(1);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (!data) return;
|
|
|
+ setQuadrantsAll(data.regions.length);
|
|
|
+ setVisited(data.visited);
|
|
|
+ }, [data]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ const updatedGeojson = updateGeojsonStyles(geojson);
|
|
|
+ setGeojson(updatedGeojson);
|
|
|
+ showScore();
|
|
|
+ }, [visited]);
|
|
|
+
|
|
|
+ const getFeatureStyle = (properties: PropertiesData) => {
|
|
|
+ const style = {
|
|
|
+ fill: 'transparent'
|
|
|
+ };
|
|
|
+
|
|
|
+ if (properties.tt == '1') {
|
|
|
+ if (properties.id > 612) {
|
|
|
+ if (Math.max(...visited) > 612) {
|
|
|
+ style.fill = 'rgba(132, 138, 68, 0.5)';
|
|
|
+ } else {
|
|
|
+ style.fill = 'rgba(21, 99, 123, 0.5)';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (visited.includes(properties.id)) {
|
|
|
+ style.fill = 'rgba(132, 138, 68, 0.5)';
|
|
|
+ } else {
|
|
|
+ style.fill = 'rgba(21, 99, 123, 0.5)';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ style.fill = 'rgba(230, 230, 230, 0.5)';
|
|
|
+ }
|
|
|
+
|
|
|
+ return style;
|
|
|
+ };
|
|
|
+
|
|
|
+ const updateGeojsonStyles = (geojson: FeatureCollection) => {
|
|
|
+ const updatedFeatures = geojson.features.map((feature) => {
|
|
|
+ const style = getFeatureStyle(feature.properties as PropertiesData);
|
|
|
+ return { ...feature, properties: { ...feature.properties, ...style } };
|
|
|
+ });
|
|
|
+
|
|
|
+ return { ...geojson, features: updatedFeatures };
|
|
|
+ };
|
|
|
+
|
|
|
+ const markQuadrant = async (qid: number) => {
|
|
|
+ let vis: 0 | 1 = 1;
|
|
|
+ if (qid > 612) {
|
|
|
+ if (Math.max(...visited) > 612) {
|
|
|
+ vis = 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (visited.includes(qid)) {
|
|
|
+ vis = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await mutateAsync(
|
|
|
+ { token, qid, visited: vis },
|
|
|
+ {
|
|
|
+ onSuccess: () => {
|
|
|
+ if (vis == 0) {
|
|
|
+ quadRemove(qid);
|
|
|
+ } else {
|
|
|
+ quadAdd(qid);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Failed to update kye state', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const quadAdd = (qid: number) => {
|
|
|
+ setVisited((prevVisited) => {
|
|
|
+ if (qid > 612) {
|
|
|
+ const newVisited = [...prevVisited];
|
|
|
+ for (let i = 613; i < 649; i++) {
|
|
|
+ if (!newVisited.includes(i)) {
|
|
|
+ newVisited.push(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return newVisited;
|
|
|
+ } else {
|
|
|
+ if (!prevVisited.includes(qid)) {
|
|
|
+ return [...prevVisited, qid];
|
|
|
+ }
|
|
|
+ return prevVisited;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const quadRemove = (qid: number) => {
|
|
|
+ setVisited((prevVisited) => {
|
|
|
+ if (qid > 612) {
|
|
|
+ return prevVisited.filter((id) => id < 613 || id > 648);
|
|
|
+ } else {
|
|
|
+ return prevVisited.filter((id) => id !== qid);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const showScore = () => {
|
|
|
+ let baseList = visited.filter((id) => id < 613);
|
|
|
+ let score = baseList.length;
|
|
|
+ if (Math.max(...visited) > 612) {
|
|
|
+ score += 1;
|
|
|
+ }
|
|
|
+ let calc = Math.round((score / quadrantsAll) * 10000) / 100;
|
|
|
+ setScore({ base: score, percentage: calc });
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <SafeAreaView style={{ height: '100%' }}>
|
|
|
+ <View style={styles.wrapper}>
|
|
|
+ <Header label={'My Earth'} />
|
|
|
+ <View style={styles.score}>
|
|
|
+ <Text style={[styles.scoreText, { fontWeight: 'bold' }]}>Your score: {score.base}</Text>
|
|
|
+ <Text style={[styles.scoreText, { fontSize: 14 }]}>{`(${score.percentage}%)`}</Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <View style={styles.container}>
|
|
|
+ <MapView
|
|
|
+ style={styles.map}
|
|
|
+ showsMyLocationButton={false}
|
|
|
+ showsCompass={false}
|
|
|
+ zoomControlEnabled={false}
|
|
|
+ mapType={Platform.OS == 'android' ? 'none' : 'standard'}
|
|
|
+ maxZoomLevel={15}
|
|
|
+ minZoomLevel={0}
|
|
|
+ initialRegion={{
|
|
|
+ latitude: 0,
|
|
|
+ longitude: 0,
|
|
|
+ latitudeDelta: 180,
|
|
|
+ longitudeDelta: 180
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <UrlTile
|
|
|
+ urlTemplate={`${MAP_HOST}/tiles_osm/{z}/{x}/{y}`}
|
|
|
+ maximumZ={15}
|
|
|
+ maximumNativeZ={13}
|
|
|
+ shouldReplaceMapContent
|
|
|
+ minimumZ={0}
|
|
|
+ />
|
|
|
+ <Geojson
|
|
|
+ geojson={geojson as any}
|
|
|
+ zIndex={1}
|
|
|
+ tappable={true}
|
|
|
+ onPress={(event) => {
|
|
|
+ markQuadrant(event.feature.properties?.id);
|
|
|
+ }}
|
|
|
+ tracksViewChanges={false}
|
|
|
+ />
|
|
|
+ </MapView>
|
|
|
+ </View>
|
|
|
+ </SafeAreaView>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default EarthScreen;
|