index.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { View, Text, TouchableOpacity, FlatList } from 'react-native';
  3. import * as Progress from 'react-native-progress';
  4. import { useFocusEffect } from '@react-navigation/native';
  5. import moment from 'moment';
  6. import { EditNmModal, Header, PageWrapper } from 'src/components';
  7. import { CustomButton } from '../Components';
  8. import { NmRegionItem } from '../Components/MyRegionsItems/NmRegionItem';
  9. import { RegionItem } from '../Components/MyRegionsItems/RegionItem';
  10. import MegaregionsModal from '../Components/MegaregionsModal';
  11. import { StoreType, storage } from 'src/storage';
  12. import { NmRegion, TCCRegion } from '../utils/types';
  13. import { Colors } from 'src/theme';
  14. import { styles } from './styles';
  15. import {
  16. useGetMegaregionsQuery,
  17. useGetRegionQeQuery,
  18. usePostSetNmRegionMutation,
  19. usePostSetTCCRegionMutation
  20. } from '@api/myRegions';
  21. import { qualityOptions } from '../utils/constants';
  22. import ChevronIcon from 'assets/icons/travels-screens/down-arrow.svg';
  23. const RegionsScreen = () => {
  24. const token = storage.get('token', StoreType.STRING) as string;
  25. const { data: megaregions } = useGetMegaregionsQuery(token, true);
  26. const [megaSelectorVisible, setMegaSelectorVisible] = useState(false);
  27. const [selectedMega, setSelectedMega] = useState<{ name: string; id: number }>({
  28. id: 1,
  29. name: 'SOUTHERN EUROPE'
  30. });
  31. const { data: regionsQe } = useGetRegionQeQuery(selectedMega.id, String(token), true);
  32. const [total, setTotal] = useState(0);
  33. const [isEditModalVisible, setIsEditModalVisible] = useState(false);
  34. const [contentIndex, setContentIndex] = useState(0);
  35. const [nmRegions, setNmRegions] = useState<NmRegion[] | null>(null);
  36. const [filteredNmRegions, setFilteredNmRegions] = useState<NmRegion[] | null>(null);
  37. const [tccRegions, setTccRegions] = useState<TCCRegion[] | null>(null);
  38. const [filteredTccRegions, setFilteredTccRegions] = useState<TCCRegion[] | null>(null);
  39. const { mutate: updateNM } = usePostSetNmRegionMutation();
  40. const { mutate: updateTCC } = usePostSetTCCRegionMutation();
  41. const [modalState, setModalState] = useState({
  42. selectedFirstYear: 2021,
  43. selectedLastYear: 2021,
  44. selectedQuality: qualityOptions[2],
  45. selectedNoOfVisits: 1,
  46. years: [],
  47. id: null
  48. });
  49. useEffect(() => {
  50. const currentYear = moment().year();
  51. let yearSelector: { label: string; value: number }[] = [{ label: 'visited', value: 1 }];
  52. for (let i = currentYear; i >= 1951; i--) {
  53. yearSelector.push({ label: i.toString(), value: i });
  54. }
  55. handleModalStateChange({ years: yearSelector });
  56. }, []);
  57. const handleModalStateChange = (updates: { [key: string]: any }) => {
  58. setModalState((prevState) => ({ ...prevState, ...updates }));
  59. };
  60. const handleOpenEditModal = (item: NmRegion) => {
  61. handleModalStateChange({
  62. selectedFirstYear: item.year,
  63. selectedLastYear: item.last,
  64. selectedQuality:
  65. qualityOptions.find((quality) => quality.id === item.quality) || qualityOptions[2],
  66. selectedNoOfVisits: item.visits || 1,
  67. id: item.id
  68. });
  69. setIsEditModalVisible(true);
  70. };
  71. const handleUpdateNM = useCallback(
  72. (id: number, first: number, last: number, visits: number, quality: number) => {
  73. const updatedNM = nmRegions?.map((item) => {
  74. if (item.id === id) {
  75. return {
  76. ...item,
  77. year: first,
  78. last,
  79. quality,
  80. visits
  81. };
  82. }
  83. return item;
  84. });
  85. const updatedNMData = {
  86. token,
  87. region: id,
  88. first,
  89. last,
  90. visits,
  91. quality
  92. };
  93. updateNM(updatedNMData);
  94. updatedNM && setNmRegions(updatedNM);
  95. },
  96. [nmRegions]
  97. );
  98. const handleUpdateTCC = useCallback(
  99. (region: number, visits: 0 | 1) => {
  100. const updatedTCC = tccRegions?.map((item) => {
  101. if (item.id === region) {
  102. return {
  103. ...item,
  104. visited: visits
  105. };
  106. }
  107. return item;
  108. });
  109. const updatedTCCData = {
  110. token,
  111. region,
  112. visits
  113. };
  114. updateTCC(updatedTCCData);
  115. updatedTCC && setTccRegions(updatedTCC);
  116. },
  117. [tccRegions]
  118. );
  119. useEffect(() => {
  120. if (nmRegions && nmRegions.length && token) {
  121. calcTotalCountries();
  122. }
  123. }, [nmRegions]);
  124. useEffect(() => {
  125. if (regionsQe && regionsQe.result === 'OK') {
  126. setNmRegions(regionsQe.data.out_regs);
  127. setTccRegions(regionsQe.data.out_tcc);
  128. }
  129. }, [regionsQe]);
  130. useEffect(() => {
  131. if (megaregions && megaregions.result === 'OK') {
  132. setContentIndex(0);
  133. }
  134. }, [selectedMega]);
  135. useEffect(() => {
  136. switch (contentIndex) {
  137. case 0:
  138. setFilteredNmRegions(nmRegions);
  139. setFilteredTccRegions(tccRegions);
  140. break;
  141. case 1:
  142. setFilteredNmRegions(nmRegions?.filter((item) => item.visits <= 0) || []);
  143. setFilteredTccRegions(tccRegions?.filter((item) => item.visited <= 0) || []);
  144. break;
  145. case 2:
  146. setFilteredNmRegions(nmRegions?.filter((item) => item.visits > 0) || []);
  147. setFilteredTccRegions(tccRegions?.filter((item) => item.visited > 0) || []);
  148. break;
  149. }
  150. }, [contentIndex, nmRegions, tccRegions]);
  151. useFocusEffect(
  152. useCallback(() => {
  153. if (megaregions && megaregions.result === 'OK') {
  154. setSelectedMega(megaregions.data[1]);
  155. }
  156. }, [megaregions])
  157. );
  158. const calcTotalCountries = () => {
  159. const visited = nmRegions?.filter((item) => item.visits > 0).length || 0;
  160. setTotal(visited);
  161. };
  162. const renderItem = ({ item }: { item: NmRegion }) => (
  163. <NmRegionItem item={item} openEditModal={handleOpenEditModal} updateNM={handleUpdateNM} token={token} />
  164. );
  165. return (
  166. <PageWrapper>
  167. <Header label="Regions" />
  168. <TouchableOpacity style={styles.megaSelector} onPress={() => setMegaSelectorVisible(true)}>
  169. <Text style={styles.megaButtonText}>{selectedMega?.name}</Text>
  170. <ChevronIcon width={18} height={18} />
  171. </TouchableOpacity>
  172. {token && (
  173. <View style={styles.buttonContainer}>
  174. <CustomButton
  175. title="All"
  176. onPress={() => setContentIndex(0)}
  177. isActive={contentIndex === 0}
  178. />
  179. <CustomButton
  180. title="Not visited"
  181. onPress={() => setContentIndex(1)}
  182. isActive={contentIndex === 1}
  183. />
  184. <CustomButton
  185. title="Visited"
  186. onPress={() => setContentIndex(2)}
  187. isActive={contentIndex === 2}
  188. />
  189. </View>
  190. )}
  191. <View style={styles.progressHeader}>
  192. <Text style={styles.textSmall}>Visited regions</Text>
  193. <Text style={styles.textSmall}>
  194. {nmRegions?.length
  195. ? `${total}/${nmRegions.length} • ${((total * 100) / nmRegions.length).toFixed(2)}%`
  196. : '0/0 • 100%'}
  197. </Text>
  198. </View>
  199. <Progress.Bar
  200. progress={nmRegions?.length ? total / nmRegions.length : 1}
  201. width={null}
  202. height={4}
  203. color={Colors.DARK_BLUE}
  204. borderWidth={0}
  205. borderRadius={5}
  206. unfilledColor={Colors.FILL_LIGHT}
  207. />
  208. {filteredNmRegions && (filteredNmRegions?.length || filteredTccRegions?.length) ? (
  209. <FlatList
  210. data={filteredNmRegions}
  211. renderItem={renderItem}
  212. keyExtractor={(item) => item.id.toString()}
  213. showsVerticalScrollIndicator={false}
  214. style={{ paddingVertical: 8 }}
  215. ListFooterComponent={
  216. filteredTccRegions && filteredTccRegions.length ? (
  217. <View style={{ marginVertical: 8 }}>
  218. <Text style={[styles.textMedium, { textAlign: 'center' }]}>TCC regions</Text>
  219. {filteredTccRegions?.map((item) => (
  220. <RegionItem item={item} updateRegion={handleUpdateTCC} key={item.id} token={token} />
  221. ))}
  222. </View>
  223. ) : null
  224. }
  225. />
  226. ) : null}
  227. <MegaregionsModal
  228. isVisible={megaSelectorVisible}
  229. onClose={() => setMegaSelectorVisible(false)}
  230. onSelect={(object) => {
  231. setMegaSelectorVisible(false);
  232. setSelectedMega(object);
  233. }}
  234. data={megaregions?.data ?? []}
  235. />
  236. <EditNmModal
  237. isVisible={isEditModalVisible}
  238. onClose={() => setIsEditModalVisible(false)}
  239. modalState={modalState}
  240. updateModalState={handleModalStateChange}
  241. updateNM={handleUpdateNM}
  242. />
  243. </PageWrapper>
  244. );
  245. };
  246. export default RegionsScreen;