index.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { View, Text, TouchableOpacity, ScrollView, FlatList } from 'react-native';
  3. import ReactModal from 'react-native-modal';
  4. import * as Progress from 'react-native-progress';
  5. import { useFocusEffect } from '@react-navigation/native';
  6. import { Dropdown } from 'react-native-searchable-dropdown-kj';
  7. import moment from 'moment';
  8. import { Button, Header, PageWrapper } from 'src/components';
  9. import { CustomButton } from '../Components';
  10. import { StoreType, storage } from 'src/storage';
  11. import { NmRegion, TCCRegion } from '../utils/types';
  12. import { Colors } from 'src/theme';
  13. import { styles } from './styles';
  14. import {
  15. useGetMegaregionsQuery,
  16. useGetRegionQeQuery,
  17. usePostSetNmRegionMutation,
  18. usePostSetTCCRegionMutation
  19. } from '@api/myRegions';
  20. import { ButtonVariants } from 'src/types/components';
  21. import { noOfVisits, qualityOptions } from '../utils/constants';
  22. import ChevronIcon from 'assets/icons/travels-screens/down-arrow.svg';
  23. import AddImgSvg from 'assets/icons/travels-screens/add-img.svg';
  24. import { NmRegionItem } from '../Components/MyRegionsItems/NmRegionItem';
  25. import { TccRegionItem } from '../Components/MyRegionsItems/TccRegionItem';
  26. const RegionsScreen = () => {
  27. const token = storage.get('token', StoreType.STRING) as string;
  28. const { data: megaregions } = useGetMegaregionsQuery(token, true);
  29. const [megaSelectorVisible, setMegaSelectorVisible] = useState(false);
  30. const [selectedMega, setSelectedMega] = useState<{ name: string; id: number }>({
  31. id: 1,
  32. name: 'SOUTHERN EUROPE'
  33. });
  34. const { data: regionsQe } = useGetRegionQeQuery(selectedMega.id, token, true);
  35. const [total, setTotal] = useState(0);
  36. const [isEditModalVisible, setIsEditModalVisible] = useState(false);
  37. const [currentItem, setCurrentItem] = useState<NmRegion | null>(null);
  38. const [contentIndex, setContentIndex] = useState(0);
  39. const [nmRegions, setNmRegions] = useState<NmRegion[] | null>(null);
  40. const [filteredNmRegions, setFilteredNmRegions] = useState<NmRegion[] | null>(null);
  41. const [tccRegions, setTccRegions] = useState<TCCRegion[] | null>(null);
  42. const [filteredTccRegions, setFilteredTccRegions] = useState<TCCRegion[] | null>(null);
  43. const { mutate: updateNM } = usePostSetNmRegionMutation();
  44. const { mutate: updateTCC } = usePostSetTCCRegionMutation();
  45. const [selectedQuality, setSelectedQuality] = useState(qualityOptions[2]);
  46. const [selectedFirstYear, setSelectedFirstYear] = useState(1);
  47. const [selectedLastYear, setSelectedLastYear] = useState(1);
  48. const [years, setYears] = useState<{ label: string; value: number }[]>([]);
  49. const [selectedNoOfVisits, setSelectedNoOfVisits] = useState(1);
  50. const handleOpenEditModal = (item: NmRegion) => {
  51. setCurrentItem(item);
  52. setSelectedFirstYear(item.year);
  53. setSelectedLastYear(item.last);
  54. setSelectedNoOfVisits(item.visits);
  55. setSelectedQuality(
  56. qualityOptions.find((quality) => quality.id === item.quality) || qualityOptions[2]
  57. );
  58. setIsEditModalVisible(true);
  59. };
  60. const handleUpdateNM = useCallback(
  61. (region: number, first: number, last: number, visits: number, quality: number) => {
  62. const updatedNM = nmRegions?.map((item) => {
  63. if (item.id === region) {
  64. return {
  65. ...item,
  66. year: first,
  67. last,
  68. quality,
  69. visits
  70. };
  71. }
  72. return item;
  73. });
  74. const updatedNMData = {
  75. token,
  76. region,
  77. first,
  78. last,
  79. visits,
  80. quality
  81. };
  82. updateNM(updatedNMData);
  83. updatedNM && setNmRegions(updatedNM);
  84. },
  85. [nmRegions]
  86. );
  87. const handleUpdateTCC = useCallback(
  88. (region: number, visits: 0 | 1) => {
  89. const updatedTCC = tccRegions?.map((item) => {
  90. if (item.id === region) {
  91. return {
  92. ...item,
  93. visited: visits
  94. };
  95. }
  96. return item;
  97. });
  98. const updatedTCCData = {
  99. token,
  100. region,
  101. visits
  102. };
  103. updateTCC(updatedTCCData);
  104. updatedTCC && setTccRegions(updatedTCC);
  105. },
  106. [tccRegions]
  107. );
  108. useEffect(() => {
  109. if (nmRegions && nmRegions.length) {
  110. calcTotalCountries();
  111. }
  112. }, [nmRegions]);
  113. useEffect(() => {
  114. if (regionsQe && regionsQe.result === 'OK') {
  115. setNmRegions(regionsQe.data.out_regs);
  116. setTccRegions(regionsQe.data.out_tcc);
  117. }
  118. }, [regionsQe]);
  119. useEffect(() => {
  120. if (megaregions && megaregions.result === 'OK') {
  121. setContentIndex(0);
  122. }
  123. }, [selectedMega]);
  124. useEffect(() => {
  125. switch (contentIndex) {
  126. case 0:
  127. setFilteredNmRegions(nmRegions);
  128. setFilteredTccRegions(tccRegions);
  129. break;
  130. case 1:
  131. setFilteredNmRegions(nmRegions?.filter((item) => item.visits <= 0) || []);
  132. setFilteredTccRegions(tccRegions?.filter((item) => item.visited <= 0) || []);
  133. break;
  134. case 2:
  135. setFilteredNmRegions(nmRegions?.filter((item) => item.visits > 0) || []);
  136. setFilteredTccRegions(tccRegions?.filter((item) => item.visited > 0) || []);
  137. break;
  138. }
  139. }, [contentIndex, nmRegions, tccRegions]);
  140. useFocusEffect(
  141. useCallback(() => {
  142. if (megaregions && megaregions.result === 'OK') {
  143. setSelectedMega(megaregions.data[1]);
  144. const currentYear = moment().year();
  145. let yearSelector: { label: string; value: number }[] = [{ label: 'visited', value: 1 }];
  146. for (let i = currentYear; i >= 1951; i--) {
  147. yearSelector.push({ label: i.toString(), value: i });
  148. }
  149. setYears(yearSelector);
  150. }
  151. }, [megaregions])
  152. );
  153. const calcTotalCountries = () => {
  154. const visited = nmRegions?.filter((item) => item.visits > 0).length || 0;
  155. setTotal(visited);
  156. };
  157. const renderItem = ({ item }: { item: NmRegion }) => (
  158. <NmRegionItem item={item} openEditModal={handleOpenEditModal} updateNM={handleUpdateNM} />
  159. );
  160. const renderOption = (name: string) => (
  161. <View style={styles.dropdownOption}>
  162. <Text style={styles.placeholderStyle}>{name}</Text>
  163. </View>
  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. <View style={styles.buttonContainer}>
  173. <CustomButton
  174. title="All"
  175. onPress={() => setContentIndex(0)}
  176. isActive={contentIndex === 0}
  177. />
  178. <CustomButton
  179. title="Not visited"
  180. onPress={() => setContentIndex(1)}
  181. isActive={contentIndex === 1}
  182. />
  183. <CustomButton
  184. title="Visited"
  185. onPress={() => setContentIndex(2)}
  186. isActive={contentIndex === 2}
  187. />
  188. </View>
  189. <View style={styles.progressHeader}>
  190. <Text style={styles.textSmall}>Visited regions</Text>
  191. <Text style={styles.textSmall}>
  192. {nmRegions?.length
  193. ? `${total}/${nmRegions.length} • ${((total * 100) / nmRegions.length).toFixed(2)}%`
  194. : '0/0 • 100%'}
  195. </Text>
  196. </View>
  197. <Progress.Bar
  198. progress={nmRegions?.length ? total / nmRegions.length : 1}
  199. width={null}
  200. height={4}
  201. color={Colors.DARK_BLUE}
  202. borderWidth={0}
  203. borderRadius={5}
  204. unfilledColor={Colors.DARK_LIGHT}
  205. />
  206. {filteredNmRegions && (filteredNmRegions?.length || filteredTccRegions?.length) ? (
  207. <FlatList
  208. data={filteredNmRegions}
  209. renderItem={renderItem}
  210. keyExtractor={(item) => item.id.toString()}
  211. showsVerticalScrollIndicator={false}
  212. style={{ paddingTop: 8, marginBottom: 16 }}
  213. ListFooterComponent={
  214. filteredTccRegions && filteredTccRegions.length ? (
  215. <View style={{ marginTop: 8 }}>
  216. <Text style={[styles.textMedium, { textAlign: 'center' }]}>TCC regions</Text>
  217. {filteredTccRegions?.map((item) => (
  218. <TccRegionItem item={item} updateTCC={handleUpdateTCC} key={item.id} />
  219. ))}
  220. </View>
  221. ) : null
  222. }
  223. />
  224. ) : null}
  225. <ReactModal
  226. isVisible={megaSelectorVisible}
  227. onBackdropPress={() => setMegaSelectorVisible(false)}
  228. style={styles.modal}
  229. statusBarTranslucent={true}
  230. presentationStyle="overFullScreen"
  231. >
  232. <View style={styles.wrapper}>
  233. <ScrollView style={{ paddingBottom: 16 }} showsVerticalScrollIndicator={false}>
  234. {megaregions?.data?.map((mega) => (
  235. <TouchableOpacity
  236. key={mega.id}
  237. style={styles.btnOption}
  238. onPress={() => {
  239. setMegaSelectorVisible(false);
  240. setSelectedMega(mega);
  241. }}
  242. >
  243. <Text style={styles.btnOptionText}>{mega.name}</Text>
  244. </TouchableOpacity>
  245. ))}
  246. </ScrollView>
  247. </View>
  248. </ReactModal>
  249. <ReactModal
  250. isVisible={isEditModalVisible}
  251. onBackdropPress={() => setIsEditModalVisible(false)}
  252. style={styles.modal}
  253. statusBarTranslucent={true}
  254. presentationStyle="overFullScreen"
  255. >
  256. <View style={styles.modalContent}>
  257. <View style={styles.optionsContainer}>
  258. <View style={styles.rowWrapper}>
  259. <View style={styles.dropdownWrapper}>
  260. <Text style={styles.textSmall}>First visit</Text>
  261. <Dropdown
  262. style={styles.dropdown}
  263. placeholderStyle={styles.placeholderStyle}
  264. selectedTextStyle={styles.placeholderStyle}
  265. data={years}
  266. labelField="label"
  267. valueField="value"
  268. value={selectedFirstYear}
  269. placeholder="First visit"
  270. onChange={(item) => {
  271. setSelectedFirstYear(item.value);
  272. setSelectedLastYear(item.value);
  273. }}
  274. containerStyle={{ borderRadius: 4 }}
  275. renderItem={(item) => renderOption(item.label)}
  276. />
  277. </View>
  278. <View style={styles.dropdownWrapper}>
  279. <Text style={styles.textSmall}>Last visit</Text>
  280. <Dropdown
  281. style={styles.dropdown}
  282. placeholderStyle={styles.placeholderStyle}
  283. selectedTextStyle={styles.placeholderStyle}
  284. data={years.filter((item) => item.value >= selectedFirstYear || item.value === 1)}
  285. labelField="label"
  286. valueField="value"
  287. value={selectedLastYear}
  288. placeholder="Last visit"
  289. onChange={(item) => setSelectedLastYear(item.value)}
  290. containerStyle={{ borderRadius: 4 }}
  291. renderItem={(item) => renderOption(item.label)}
  292. />
  293. </View>
  294. </View>
  295. <View style={styles.rowWrapper}>
  296. <View style={styles.dropdownWrapper}>
  297. <Text style={styles.textSmall}>Best visit quality</Text>
  298. <Dropdown
  299. style={styles.dropdown}
  300. placeholderStyle={styles.placeholderStyle}
  301. containerStyle={{ borderRadius: 4 }}
  302. selectedTextStyle={styles.placeholderStyle}
  303. data={qualityOptions}
  304. labelField="name"
  305. valueField="id"
  306. value={selectedQuality.id}
  307. placeholder="Best visit quality"
  308. onChange={(item) => setSelectedQuality(item)}
  309. renderItem={(item) => renderOption(item.name)}
  310. />
  311. </View>
  312. <View style={styles.dropdownWrapper}>
  313. <Text style={styles.textSmall}>No of visits</Text>
  314. <Dropdown
  315. style={styles.dropdown}
  316. placeholderStyle={styles.placeholderStyle}
  317. selectedTextStyle={styles.placeholderStyle}
  318. data={noOfVisits}
  319. labelField="label"
  320. valueField="value"
  321. value={selectedNoOfVisits}
  322. placeholder="No of visits"
  323. onChange={(item) => setSelectedNoOfVisits(item.value)}
  324. containerStyle={{ borderRadius: 4 }}
  325. renderItem={(item) => renderOption(item.label)}
  326. />
  327. </View>
  328. </View>
  329. </View>
  330. {/* <View style={styles.photosContent}>
  331. <Text style={styles.textMedium}>Photos</Text>
  332. <TouchableOpacity style={styles.addImgBtn}>
  333. <AddImgSvg fill={Colors.DARK_BLUE} />
  334. <Text style={styles.textSmall}>Add</Text>
  335. </TouchableOpacity>
  336. </View> */}
  337. <Button
  338. children="Done"
  339. onPress={() => {
  340. setIsEditModalVisible(false);
  341. currentItem?.id &&
  342. handleUpdateNM(
  343. currentItem.id,
  344. selectedFirstYear,
  345. selectedLastYear,
  346. selectedNoOfVisits,
  347. selectedQuality.id
  348. );
  349. }}
  350. />
  351. <Button
  352. children="Close"
  353. onPress={() => setIsEditModalVisible(false)}
  354. variant={ButtonVariants.OPACITY}
  355. containerStyles={styles.closeBtn}
  356. textStyles={{ color: Colors.DARK_BLUE }}
  357. />
  358. </View>
  359. </ReactModal>
  360. </PageWrapper>
  361. );
  362. };
  363. export default RegionsScreen;