index.tsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import { useEffect, useRef } from 'react';
  2. import { Text, TouchableOpacity, View, Image, Animated } from 'react-native';
  3. import MarkIcon from 'assets/icons/mark.svg';
  4. import EditSvg from 'assets/icons/travels-screens/pen-to-square.svg';
  5. import CalendarSvg from 'assets/icons/travels-screens/calendar.svg';
  6. import RotateSvg from 'assets/icons/travels-screens/rotate.svg';
  7. import CheckSvg from 'assets/icons/travels-screens/circle-check.svg';
  8. import CheckRegularSvg from 'assets/icons/travels-screens/circle-check-regular.svg';
  9. import { styles } from './style';
  10. import React from 'react';
  11. import { Colors } from 'src/theme';
  12. import { useNavigation } from '@react-navigation/native';
  13. import { NAVIGATION_PAGES } from 'src/types';
  14. interface Region {
  15. id: number;
  16. name: string;
  17. region_photos: string;
  18. visitors_count: number;
  19. }
  20. interface RegionPopupProps {
  21. region: Region;
  22. userAvatars: string[];
  23. userData: any;
  24. openEditModal: () => void;
  25. updateNM: (region: number, first: number, last: number, visits: number, quality: number) => void;
  26. updateDare: (region: number, visits: 0 | 1) => void;
  27. disabled?: boolean;
  28. updateSlow: (id: number, v: boolean, s11: boolean, s31: boolean, s101: boolean) => void;
  29. openEditSlowModal: () => void;
  30. }
  31. const RegionPopup: React.FC<RegionPopupProps> = ({
  32. region,
  33. userAvatars,
  34. userData,
  35. openEditModal,
  36. updateNM,
  37. updateDare,
  38. disabled,
  39. updateSlow,
  40. openEditSlowModal
  41. }) => {
  42. const fadeAnim = useRef(new Animated.Value(0)).current;
  43. const navigation = useNavigation();
  44. useEffect(() => {
  45. Animated.timing(fadeAnim, {
  46. toValue: 1,
  47. duration: 300,
  48. useNativeDriver: true
  49. }).start();
  50. }, [fadeAnim]);
  51. const splitRegionName = (fullName: string) => {
  52. const [name, ...rest] = fullName?.split(/ – | - /);
  53. const subname = rest?.join(' - ');
  54. return {
  55. regionTitle: name,
  56. regionSubtitle: subname ? subname : ''
  57. };
  58. };
  59. const { regionTitle, regionSubtitle } = splitRegionName(region.name);
  60. const regionImg = JSON.parse(region.region_photos)[0];
  61. function formatNumber(number: number) {
  62. if (number >= 1000 && number < 10000) {
  63. return (number / 1000).toFixed(1) + 'k';
  64. } else if (number >= 10000) {
  65. return (number / 1000).toFixed(0) + 'k';
  66. }
  67. return number.toString();
  68. }
  69. const formattedCount = formatNumber(region.visitors_count);
  70. const renderDurationIcon = (condition: 0 | 1) =>
  71. condition ? <CheckSvg fill={Colors.DARK_BLUE} /> : <CheckRegularSvg />;
  72. return (
  73. <Animated.View style={[styles.popupContainer, { opacity: fadeAnim }]}>
  74. <TouchableOpacity
  75. onPress={() => {
  76. if (userData?.type === 'countries') {
  77. navigation.navigate(
  78. ...([
  79. NAVIGATION_PAGES.COUNTRY_PREVIEW,
  80. {
  81. regionId: region.id,
  82. type: 'country',
  83. disabled
  84. }
  85. ] as never)
  86. );
  87. } else {
  88. navigation.navigate(
  89. ...([
  90. NAVIGATION_PAGES.REGION_PREVIEW,
  91. {
  92. regionId: region.id,
  93. type: userData?.type,
  94. disabled
  95. }
  96. ] as never)
  97. );
  98. }
  99. }}
  100. style={{ flex: 1 }}
  101. >
  102. <View style={styles.regionInfoContainer}>
  103. {regionImg && <Image source={{ uri: regionImg }} style={styles.regionImage} />}
  104. <View style={styles.regionTextContainer}>
  105. <Text style={styles.regionTitle}>{regionTitle}</Text>
  106. {regionSubtitle && <Text style={styles.regionSubtitle}>{regionSubtitle}</Text>}
  107. </View>
  108. </View>
  109. <View>
  110. <View style={styles.separator} />
  111. </View>
  112. <View style={styles.bottomContainer}>
  113. <View style={styles.userContainer}>
  114. {userData?.visited && userData?.first_visit_year > 1 && !disabled && (
  115. <View style={styles.infoContent}>
  116. <CalendarSvg height={18} width={18} fill={Colors.DARK_BLUE} />
  117. <Text style={styles.visitedButtonText}>{userData?.first_visit_year}</Text>
  118. </View>
  119. )}
  120. {userData?.visited && userData?.type === 'nm' && !disabled && (
  121. <View style={styles.infoContent}>
  122. <RotateSvg fill={Colors.DARK_BLUE} />
  123. <Text style={styles.visitedButtonText}>
  124. {userData.no_of_visits >= 10 ? '10+' : userData.no_of_visits}
  125. </Text>
  126. </View>
  127. )}
  128. {userData?.visited && userData?.type === 'countries' && !disabled && (
  129. <View style={styles.durationContainer}>
  130. <View style={styles.durationItem}>
  131. {renderDurationIcon(userData.slow11)}
  132. <Text style={styles.visitDuration}>11+ days</Text>
  133. </View>
  134. <View style={styles.durationItem}>
  135. {renderDurationIcon(userData.slow31)}
  136. <Text style={styles.visitDuration}>31+ days</Text>
  137. </View>
  138. <View style={styles.durationItem}>
  139. {renderDurationIcon(userData.slow101)}
  140. <Text style={styles.visitDuration}>101+ days</Text>
  141. </View>
  142. </View>
  143. )}
  144. {(!userData?.visited || userData?.type === 'dare' || disabled) && (
  145. <View style={styles.userImageContainer}>
  146. {userAvatars?.map((avatar, index) => (
  147. <Image key={index} source={{ uri: avatar }} style={styles.userImage} />
  148. ))}
  149. <View style={styles.userCountContainer}>
  150. <Text style={styles.userCount}>{formattedCount}</Text>
  151. </View>
  152. </View>
  153. )}
  154. </View>
  155. <View style={styles.btnContainer}>
  156. {userData?.visited && userData?.type !== 'dare' && !disabled ? (
  157. <TouchableOpacity
  158. onPress={userData?.type === 'countries' ? openEditSlowModal : openEditModal}
  159. style={styles.editBtn}
  160. >
  161. <EditSvg width={14} height={14} />
  162. </TouchableOpacity>
  163. ) : null}
  164. <TouchableOpacity
  165. style={[
  166. styles.btn,
  167. userData?.visited && !disabled ? styles.visitedButton : styles.markVisitedButton
  168. ]}
  169. onPress={() =>
  170. userData?.type === 'nm'
  171. ? updateNM(
  172. region.id,
  173. userData.visited ? 0 : 1,
  174. userData.visited ? 0 : 1,
  175. userData.visited ? 0 : 1,
  176. 3
  177. )
  178. : userData?.type === 'countries'
  179. ? updateSlow(
  180. region.id,
  181. !userData.visited,
  182. Boolean(userData.slow11),
  183. Boolean(userData.slow31),
  184. Boolean(userData.slow101)
  185. )
  186. : updateDare(region.id, userData.visited ? 0 : 1)
  187. }
  188. >
  189. {userData?.visited && !disabled ? (
  190. <View style={styles.visitedContainer}>
  191. <MarkIcon width={16} height={16} />
  192. <Text style={styles.visitedButtonText}>Visited</Text>
  193. </View>
  194. ) : (
  195. <Text style={[styles.markVisitedButtonText]}>Mark Visited</Text>
  196. )}
  197. </TouchableOpacity>
  198. </View>
  199. </View>
  200. </TouchableOpacity>
  201. </Animated.View>
  202. );
  203. };
  204. export default React.memo(RegionPopup);