index.tsx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. import { NavigationProp, useFocusEffect } from '@react-navigation/native';
  2. import React, { FC, useCallback, useEffect, useState } from 'react';
  3. import { ActivityIndicator } from 'react-native';
  4. import { Header, HorizontalTabView, Loading, PageWrapper, WarningModal } from 'src/components';
  5. import { Colors } from 'src/theme';
  6. import { FlashList } from '@shopify/flash-list';
  7. import { StoreType, storage } from 'src/storage';
  8. import { FilterButton, FilterModal } from '../../TravellersScreen/Components/FilterModal';
  9. import { RankingDropdown } from '../../TravellersScreen/utils/types';
  10. import { dataRanking } from '../../TravellersScreen/utils';
  11. import {
  12. useGetMyFriendsMutation,
  13. usePostHideShowRequestMutation,
  14. usePostUpdateFriendStatusMutation
  15. } from '@api/friends';
  16. import { FriendsProfile } from './FriendsProfile';
  17. import { useNotification } from 'src/contexts/NotificationContext';
  18. type Props = {
  19. navigation: NavigationProp<any>;
  20. route: any;
  21. };
  22. type Routes = {
  23. key: 'friends' | 'received' | 'sent';
  24. title: string;
  25. };
  26. const MyFriendsScreen: FC<Props> = ({ navigation }) => {
  27. const token = storage.get('token', StoreType.STRING) as string;
  28. const { isNotificationActive, updateNotificationStatus } = useNotification();
  29. const { mutateAsync: getMyFriends } = useGetMyFriendsMutation();
  30. const [loading, setLoading] = useState(true);
  31. const [isModalVisible, setModalVisible] = useState(false);
  32. const [confirmedValueRanking, setConfirmedValueRanking] = useState<RankingDropdown | null>();
  33. const [masterCountries, setMasterCountries] = useState<any>([]);
  34. const [maxPages, setMaxPages] = useState(1);
  35. const [page, setPage] = useState(0);
  36. const [isLoadingMore, setIsLoadingMore] = useState(false);
  37. const [filter, setFilter] = useState<{
  38. age: number | undefined;
  39. ranking: string | undefined;
  40. country: string | undefined;
  41. }>({ age: undefined, ranking: undefined, country: undefined });
  42. const [index, setIndex] = useState(0);
  43. const routes: Routes[] = [
  44. { key: 'friends', title: 'My friends' },
  45. { key: 'received', title: 'Received requests' },
  46. { key: 'sent', title: 'Sent requests' }
  47. ];
  48. const [users, setUsers] = useState<{ [key in 'friends' | 'received' | 'sent']: any[] }>({
  49. friends: [],
  50. received: [],
  51. sent: []
  52. });
  53. const { mutateAsync: updateFriendStatus } = usePostUpdateFriendStatusMutation();
  54. const { mutateAsync: hideShowRequest } = usePostHideShowRequestMutation();
  55. useEffect(() => {
  56. if (filter.age || filter.ranking || filter.country) {
  57. applySort();
  58. }
  59. }, [filter]);
  60. useEffect(() => {
  61. fetchUsers();
  62. setFilter({
  63. age: undefined,
  64. ranking: undefined,
  65. country: undefined
  66. });
  67. }, [index]);
  68. useFocusEffect(
  69. useCallback(() => {
  70. fetchUsers();
  71. }, [])
  72. );
  73. useEffect(() => {
  74. const getNextPage = async () => {
  75. await getMyFriends(
  76. {
  77. token,
  78. type: routes[index].key,
  79. page,
  80. sort: filter.ranking,
  81. age: filter.age,
  82. country: filter.country
  83. },
  84. {
  85. onSuccess: (data) => {
  86. setIsLoadingMore(false);
  87. setUsers((prevState) => {
  88. return {
  89. ...prevState,
  90. [routes[index].key]: [
  91. ...prevState[routes[index].key],
  92. ...data[routes[index].key].users
  93. ]
  94. };
  95. });
  96. }
  97. }
  98. );
  99. };
  100. if (page !== 0) {
  101. getNextPage();
  102. }
  103. }, [page]);
  104. const fetchUsers = async () => {
  105. await getMyFriends(
  106. {
  107. token,
  108. type: '',
  109. page: 0,
  110. sort: undefined,
  111. age: undefined,
  112. country: undefined
  113. },
  114. {
  115. onSuccess: (data) => {
  116. setUsers({
  117. friends: data.friends.users,
  118. received: data.received.users,
  119. sent: data.sent.users
  120. });
  121. setMaxPages(data[routes[index].key].max_pages);
  122. setMasterCountries(convertData(data[routes[index].key].countries) ?? []);
  123. setLoading(false);
  124. }
  125. }
  126. );
  127. };
  128. const applySort = async () => {
  129. await getMyFriends(
  130. {
  131. token,
  132. type: routes[index].key,
  133. page,
  134. sort: filter.ranking,
  135. age: filter.age,
  136. country: filter.country
  137. },
  138. {
  139. onSuccess: (data) => {
  140. setUsers((prevState) => {
  141. return {
  142. ...prevState,
  143. [routes[index].key]: data[routes[index].key].users
  144. };
  145. });
  146. setMaxPages(data[routes[index].key].max_pages);
  147. setMasterCountries(convertData(data[routes[index].key].countries) ?? []);
  148. setLoading(false);
  149. }
  150. }
  151. );
  152. };
  153. const convertData = (data: { [key: string]: { country: string; flag: string } }) => {
  154. let formatedCountries = [{ two: 'all', name: 'ALL', flag: '' }];
  155. formatedCountries.push(
  156. ...Object.entries(data).map(([key, value]) => ({
  157. two: key,
  158. name: value.country,
  159. flag: value.flag
  160. }))
  161. );
  162. return formatedCountries;
  163. };
  164. const handleEndReached = useCallback(() => {
  165. if (users && page < maxPages && !isLoadingMore && maxPages > 1) {
  166. setIsLoadingMore(true);
  167. setPage((prevPage) => prevPage + 1);
  168. }
  169. }, [users, page]);
  170. const handleUpdateFriendStatus = async (status: number, id: number) => {
  171. await updateFriendStatus(
  172. { token, id, status },
  173. {
  174. onSuccess: () => {
  175. applySort();
  176. }
  177. }
  178. );
  179. updateNotificationStatus();
  180. };
  181. const handleHideRequest = async (id: number) => {
  182. await hideShowRequest(
  183. { token, id, show: 0 },
  184. {
  185. onSuccess: () => {
  186. applySort();
  187. }
  188. }
  189. );
  190. };
  191. if (loading) return <Loading />;
  192. const ListFooter = ({ isLoading }: { isLoading: boolean }) =>
  193. isLoading ? <ActivityIndicator size="large" color={Colors.DARK_BLUE} /> : null;
  194. return (
  195. <PageWrapper>
  196. <Header
  197. label={'Friends'}
  198. rightElement={<FilterButton onPress={() => setModalVisible(!isModalVisible)} />}
  199. />
  200. <HorizontalTabView
  201. index={index}
  202. setIndex={setIndex}
  203. routes={routes}
  204. withNotification={isNotificationActive}
  205. renderScene={({ route }: { route: Routes }) => (
  206. <>
  207. <FlashList
  208. viewabilityConfig={{
  209. waitForInteraction: true,
  210. itemVisiblePercentThreshold: 50,
  211. minimumViewTime: 1000
  212. }}
  213. estimatedItemSize={50}
  214. data={users[route.key]}
  215. renderItem={({ item, index }) => (
  216. <FriendsProfile
  217. userId={item.user_id}
  218. key={index}
  219. index={index}
  220. first_name={item.first_name}
  221. last_name={item.last_name}
  222. avatar={item.avatar}
  223. date_of_birth={item.age}
  224. homebase_flag={item.flag1}
  225. homebase2_flag={item.flag2}
  226. score={[
  227. item.score_nm,
  228. item.score_un,
  229. item.score_unp,
  230. item.score_dare,
  231. item.score_tcc,
  232. item.score_deep,
  233. item.score_slow,
  234. item.score_yes,
  235. item.score_kye,
  236. item.score_whs,
  237. item.score_tbt
  238. ]}
  239. active_score={
  240. confirmedValueRanking
  241. ? confirmedValueRanking.value - 1
  242. : dataRanking[0].value - 1
  243. }
  244. tbt_score={item.score_tbt}
  245. tbt_rank={item.rank_tbt}
  246. badge_tbt={item.badge_tbt}
  247. badge_1281={item.badge_1281}
  248. badge_un={item.badge_un}
  249. auth={item.auth}
  250. type={route.key}
  251. updateFriendStatus={handleUpdateFriendStatus}
  252. status={item.friend_status}
  253. friendDbId={item.friend_db_id}
  254. hideRequest={handleHideRequest}
  255. />
  256. )}
  257. keyExtractor={(item) => item.user_id.toString()}
  258. contentContainerStyle={{ paddingBottom: 52, paddingTop: 8 }}
  259. showsVerticalScrollIndicator={false}
  260. onEndReached={handleEndReached}
  261. onEndReachedThreshold={0.2}
  262. ListFooterComponent={<ListFooter isLoading={isLoadingMore} />}
  263. />
  264. </>
  265. )}
  266. />
  267. <FilterModal
  268. isModalVisible={isModalVisible}
  269. setModalVisible={(value) => setModalVisible(value)}
  270. applyFilter={(filterAge, filterRanking, filterCountry) => {
  271. setConfirmedValueRanking(filterRanking);
  272. setPage(0);
  273. setFilter({
  274. age: filterAge?.value ? +filterAge?.value : undefined,
  275. ranking: filterRanking?.name,
  276. country:
  277. filterCountry?.two && filterCountry?.two !== 'all' ? filterCountry?.two : undefined
  278. });
  279. if (!filterAge && !filterRanking && !filterCountry) {
  280. fetchUsers();
  281. }
  282. setModalVisible(false);
  283. }}
  284. countriesData={masterCountries}
  285. />
  286. </PageWrapper>
  287. );
  288. };
  289. export default MyFriendsScreen;