index.tsx 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { View, Text, TouchableOpacity, ScrollView, FlatList, Platform } from 'react-native';
  3. import ReactModal from 'react-native-modal';
  4. import * as Progress from 'react-native-progress';
  5. import { useFocusEffect, useNavigation } from '@react-navigation/native';
  6. import CountryItem from '../Components/CountryItem';
  7. import EditModal from '../Components/EditSlowModal';
  8. import { Header, Input, PageWrapper, WarningModal } from 'src/components';
  9. import { useGetSlowQuery, usePostSetSlowMutation } from '@api/countries';
  10. import { StoreType, storage } from 'src/storage';
  11. import { SlowData } from '../utils/types';
  12. import { Colors } from 'src/theme';
  13. import { styles } from './styles';
  14. import ChevronIcon from 'assets/icons/travels-screens/down-arrow.svg';
  15. import IngoSvg from 'assets/icons/travels-screens/info.svg';
  16. import SearchIcon from '../../../../../assets/icons/search.svg';
  17. import InfoIcon from 'assets/icons/info-solid.svg';
  18. import { NAVIGATION_PAGES } from 'src/types';
  19. import { useRegion } from 'src/contexts/RegionContext';
  20. const CountriesScreen = () => {
  21. const token = storage.get('token', StoreType.STRING) as string;
  22. const { data, refetch } = useGetSlowQuery(String(token));
  23. const [megaSelectorVisible, setMegaSelectorVisible] = useState(false);
  24. const [selectedMega, setSelectedMega] = useState<{ name: string; id: number }>({
  25. name: 'ALL MEGAREGIONS',
  26. id: -1
  27. });
  28. const [total, setTotal] = useState({ slow: 0, visited: 0 });
  29. const [isEditModalVisible, setIsEditModalVisible] = useState(false);
  30. const [currentItem, setCurrentItem] = useState<SlowData | null>(null);
  31. const [infoModalVisible, setInfoModalVisible] = useState(false);
  32. const [search, setSearch] = useState<string>('');
  33. const [filteredSlow, setFilteredSlow] = useState<SlowData[] | null>(null);
  34. const navigation = useNavigation();
  35. const { handleUpdateSlowList: handleUpdateSlow, slow, setSlow, setUserData } = useRegion();
  36. const handleOpenEditModal = (item: SlowData) => {
  37. setCurrentItem(item);
  38. setIsEditModalVisible(true);
  39. };
  40. useFocusEffect(
  41. useCallback(() => {
  42. const refetchData = async () => {
  43. await refetch().then((res) => {
  44. if (res.data) {
  45. setSlow(res.data.slow);
  46. }
  47. });
  48. };
  49. if (token) {
  50. refetchData();
  51. navigation.getParent()?.setOptions({
  52. tabBarStyle: {
  53. display: 'flex',
  54. ...Platform.select({
  55. android: {
  56. height: 58
  57. }
  58. })
  59. }
  60. });
  61. }
  62. }, [token, refetch, navigation])
  63. );
  64. useEffect(() => {
  65. if (slow && slow.length) {
  66. token && calcTotalScore();
  67. let newSlowData = slow;
  68. if (search) {
  69. newSlowData =
  70. slow?.filter((item: any) => {
  71. const itemData = item.country ? item.country.toLowerCase() : ''.toLowerCase();
  72. const textData = search.toLowerCase();
  73. return itemData.indexOf(textData) > -1;
  74. }) ?? [];
  75. }
  76. setFilteredSlow(newSlowData);
  77. }
  78. }, [slow]);
  79. useEffect(() => {
  80. const refetchData = async () => {
  81. await refetch().then((res) => {
  82. if (res.data) {
  83. setSlow(res.data.slow);
  84. }
  85. });
  86. };
  87. if (data && data.result === 'OK') {
  88. setSearch('');
  89. if (selectedMega.id === -1) {
  90. refetchData();
  91. } else {
  92. setSlow(data?.slow?.filter((item) => item.mega.includes(selectedMega.id)));
  93. }
  94. }
  95. }, [selectedMega]);
  96. useEffect(() => {
  97. if (data && data.result === 'OK') {
  98. setSlow(data?.slow);
  99. }
  100. }, [data]);
  101. const searchFilter = (text: string) => {
  102. if (text) {
  103. const newData: SlowData[] | null =
  104. slow?.filter((item: any) => {
  105. const itemData = item.country ? item.country.toLowerCase() : ''.toLowerCase();
  106. const textData = text.toLowerCase();
  107. return itemData.indexOf(textData) > -1;
  108. }) ?? [];
  109. setFilteredSlow(newData);
  110. setSearch(text);
  111. } else {
  112. setFilteredSlow(slow);
  113. setSearch(text);
  114. }
  115. };
  116. const calcTotalScore = () => {
  117. let visited = 0;
  118. let slow11 = 0;
  119. let slow31 = 0;
  120. let slow101 = 0;
  121. slow?.forEach((item: SlowData) => {
  122. visited += item.visited;
  123. slow11 += item.slow11;
  124. slow31 += item.slow31;
  125. slow101 += item.slow101;
  126. });
  127. setTotal({ slow: slow11 + slow31 + slow101, visited });
  128. };
  129. const renderCountryItem = ({ item }: { item: SlowData }) => (
  130. <CountryItem
  131. item={item}
  132. updateSlow={handleUpdateSlow}
  133. openEditModal={handleOpenEditModal}
  134. token={token}
  135. setUserData={setUserData}
  136. navigation={navigation}
  137. />
  138. );
  139. return (
  140. <PageWrapper>
  141. <Header
  142. label="Countries"
  143. // rightElement={
  144. // <TouchableOpacity
  145. // onPress={() => navigation.navigate(NAVIGATION_PAGES.COUNTRIES_INFO as never)}
  146. // style={{ width: 30 }}
  147. // >
  148. // <InfoIcon />
  149. // </TouchableOpacity>
  150. // }
  151. />
  152. <TouchableOpacity style={styles.megaSelector} onPress={() => setMegaSelectorVisible(true)}>
  153. <Text style={styles.megaButtonText}>{selectedMega.name}</Text>
  154. <ChevronIcon width={18} height={18} />
  155. </TouchableOpacity>
  156. <View style={{ marginBottom: 16 }}>
  157. <Input
  158. inputMode={'search'}
  159. placeholder={'Search'}
  160. onChange={(text) => searchFilter(text)}
  161. value={search}
  162. icon={<SearchIcon fill={'#C8C8C8'} width={14} height={14} />}
  163. height={34}
  164. />
  165. </View>
  166. <View style={styles.progressHeader}>
  167. <Text style={styles.visitedCountriesCount}>Visited countries</Text>
  168. <Text style={styles.visitedCountriesCount}>
  169. {slow?.length
  170. ? `${total.visited}/${slow.length} • ${((total.visited * 100) / slow.length).toFixed(2)}%`
  171. : '0/0 • 100%'}
  172. </Text>
  173. </View>
  174. <Progress.Bar
  175. progress={slow?.length ? total.visited / slow.length : 1}
  176. width={null}
  177. height={4}
  178. color={Colors.DARK_BLUE}
  179. borderWidth={0}
  180. borderRadius={5}
  181. unfilledColor={Colors.FILL_LIGHT}
  182. />
  183. <View style={styles.slowScoreSection}>
  184. <Text style={styles.visitedCountriesCount}>SLOW score: {total.slow}</Text>
  185. <TouchableOpacity style={styles.infoBtn} onPress={() => setInfoModalVisible(true)}>
  186. <IngoSvg />
  187. </TouchableOpacity>
  188. </View>
  189. {filteredSlow && filteredSlow?.length ? (
  190. <FlatList
  191. data={filteredSlow}
  192. renderItem={renderCountryItem}
  193. keyExtractor={(item) => item.country_id.toString()}
  194. showsVerticalScrollIndicator={false}
  195. style={{ paddingTop: 8 }}
  196. />
  197. ) : null}
  198. <ReactModal
  199. isVisible={megaSelectorVisible}
  200. onBackdropPress={() => setMegaSelectorVisible(false)}
  201. style={styles.modal}
  202. statusBarTranslucent={true}
  203. presentationStyle="overFullScreen"
  204. >
  205. <View style={styles.wrapper}>
  206. <ScrollView style={{ paddingBottom: 16 }} showsVerticalScrollIndicator={false}>
  207. <TouchableOpacity
  208. style={styles.btnOption}
  209. onPress={() => {
  210. setMegaSelectorVisible(false);
  211. setSelectedMega({ name: 'ALL MEGAREGIONS', id: -1 });
  212. }}
  213. >
  214. <Text style={styles.btnOptionText}>ALL MEGAREGIONS</Text>
  215. </TouchableOpacity>
  216. {data?.megaregions?.map((mega) => (
  217. <TouchableOpacity
  218. key={mega.id}
  219. style={styles.btnOption}
  220. onPress={() => {
  221. setMegaSelectorVisible(false);
  222. setSelectedMega(mega);
  223. }}
  224. >
  225. <Text style={styles.btnOptionText}>{mega.name}</Text>
  226. </TouchableOpacity>
  227. ))}
  228. </ScrollView>
  229. </View>
  230. </ReactModal>
  231. {currentItem && (
  232. <EditModal
  233. isVisible={isEditModalVisible}
  234. onClose={() => setIsEditModalVisible(false)}
  235. item={currentItem}
  236. updateSlow={(id, v, s11, s31, s101) => handleUpdateSlow(id, v, s11, s31, s101)}
  237. />
  238. )}
  239. <WarningModal
  240. isVisible={infoModalVisible}
  241. onClose={() => setInfoModalVisible(false)}
  242. type="success"
  243. title="SLOW score"
  244. message={`Mark countries as visited.\nTell us if you stayed longer (11, 31, 101) days, this will increase your SLOW score, each longer stay should include at least 11 days countinuous stay in a country.`}
  245. />
  246. </PageWrapper>
  247. );
  248. };
  249. export default CountriesScreen;