index.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { View, Text, TouchableOpacity, FlatList } from 'react-native';
  3. import { useFocusEffect, useNavigation } from '@react-navigation/native';
  4. import * as ImagePicker from 'expo-image-picker';
  5. import { PageWrapper, Header, Modal, FlatList as List, Loading } from 'src/components';
  6. import { PhotoItem, CustomButton } from '../Components';
  7. import { useGetPhotosForUserQuery, useGetTempQuery } from '@api/photos';
  8. import { StoreType, storage } from 'src/storage';
  9. import { AllRegions, ByDateData, ByRegionData, PhotosData } from '../utils/types';
  10. import { compareDates, groupByDate } from '../utils';
  11. import { NAVIGATION_PAGES } from 'src/types';
  12. import { Colors } from 'src/theme';
  13. import { styles } from './styles';
  14. import AddImgSvg from '../../../../../assets/icons/travels-screens/add-img.svg';
  15. import ChevronIcon from '../../../../../assets/icons/travels-screens/chevron-bottom.svg';
  16. const ByRegionContent = ({
  17. data,
  18. allRegions
  19. }: {
  20. data: ByRegionData[];
  21. allRegions: AllRegions[];
  22. }) => {
  23. const [loading, setLoading] = useState(true);
  24. const [visible, setVisible] = useState(false);
  25. const [selectedRegion, setSelectedRegion] = useState<ByRegionData>();
  26. const [photos, setPhotos] = useState<ByRegionData[]>([]);
  27. useEffect(() => {
  28. if (selectedRegion?.country === 'All Regions') {
  29. setPhotos(data);
  30. } else {
  31. setPhotos(
  32. data.filter(
  33. (item) => item.country === selectedRegion?.country && item.name === selectedRegion?.name
  34. )
  35. );
  36. }
  37. }, [selectedRegion]);
  38. useFocusEffect(
  39. useCallback(() => {
  40. setPhotos(data);
  41. setLoading(false);
  42. }, [data])
  43. );
  44. if (loading) return <Loading />;
  45. return (
  46. <View style={{ flex: 1 }}>
  47. <TouchableOpacity style={styles.regionSelector} onPress={() => setVisible(true)}>
  48. <Text style={styles.regionText}>{selectedRegion?.country ?? 'All Regions'}</Text>
  49. <ChevronIcon />
  50. </TouchableOpacity>
  51. <Modal
  52. onRequestClose={() => setVisible(false)}
  53. headerTitle={'Select Region'}
  54. visible={visible}
  55. >
  56. <List
  57. itemObject={(object) => {
  58. setVisible(false);
  59. setSelectedRegion(object);
  60. }}
  61. initialData={[{ country: 'All Regions', id: 0 }, ...data]}
  62. />
  63. </Modal>
  64. <FlatList
  65. data={photos}
  66. renderItem={({ item }) => <PhotoItem item={item} allRegions={allRegions} />}
  67. keyExtractor={(item) => item.id.toString()}
  68. style={styles.listContainer}
  69. showsVerticalScrollIndicator={false}
  70. />
  71. </View>
  72. );
  73. };
  74. const ByDateContent = ({ data, allRegions }: { data: ByDateData; allRegions: AllRegions[] }) => {
  75. const [loading, setLoading] = useState<boolean>(true);
  76. const [visible, setVisible] = useState<boolean>(false);
  77. const [selectedDate, setSelectedDate] = useState<string | null>(null);
  78. const [photos, setPhotos] = useState<{ date: string; photos: PhotosData[] }[]>([]);
  79. const [filter, setFilter] = useState<string[]>([]);
  80. useEffect(() => {
  81. if (selectedDate) {
  82. setPhotos(groupByDate(data[selectedDate]));
  83. }
  84. }, [selectedDate]);
  85. useFocusEffect(
  86. useCallback(() => {
  87. const keys: string[] = Object.keys(data);
  88. if (keys.length > 0) {
  89. let sortedKeys = keys?.sort(compareDates);
  90. const firstKey = sortedKeys[0];
  91. const groupedByDate = groupByDate(data[firstKey]);
  92. setPhotos(groupedByDate);
  93. setFilter(sortedKeys);
  94. }
  95. setLoading(false);
  96. }, [data])
  97. );
  98. if (loading) return <Loading />;
  99. return (
  100. <View style={{ flex: 1 }}>
  101. <TouchableOpacity style={styles.regionSelector} onPress={() => setVisible(true)}>
  102. <Text style={styles.regionText}>{selectedDate ?? filter[0]}</Text>
  103. <ChevronIcon />
  104. </TouchableOpacity>
  105. <Modal onRequestClose={() => setVisible(false)} headerTitle={'Select Date'} visible={visible}>
  106. <List
  107. itemObject={(object) => {
  108. setVisible(false);
  109. setSelectedDate(object);
  110. }}
  111. initialData={filter}
  112. date={true}
  113. />
  114. </Modal>
  115. <FlatList
  116. data={photos}
  117. renderItem={({ item }) => <PhotoItem item={item} allRegions={allRegions} />}
  118. keyExtractor={(item) => item.date}
  119. style={styles.listContainer}
  120. showsVerticalScrollIndicator={false}
  121. />
  122. </View>
  123. );
  124. };
  125. const PhotosScreen = () => {
  126. const token = storage.get('token', StoreType.STRING) as string;
  127. const [loading, setLoading] = useState(true);
  128. const [contentIndex, setContentIndex] = useState(0);
  129. const { data, refetch } = useGetPhotosForUserQuery(token, true);
  130. const [allRegions, setAllRegions] = useState<AllRegions[]>([]);
  131. const { data: tempData, refetch: refetchTemp } = useGetTempQuery(token, true);
  132. const navigation = useNavigation();
  133. useFocusEffect(
  134. useCallback(() => {
  135. const fetchData = async () => {
  136. setLoading(true);
  137. try {
  138. await refetch().then((res) => {
  139. if (res.data?.result === 'OK') {
  140. setAllRegions(res?.data?.all_regions);
  141. }
  142. });
  143. } catch (error) {
  144. console.error(error);
  145. } finally {
  146. setLoading(false);
  147. }
  148. };
  149. fetchData();
  150. }, [refetch])
  151. );
  152. if (loading) return <Loading />;
  153. const renderContent = () => {
  154. switch (contentIndex) {
  155. case 0:
  156. return <ByRegionContent data={data?.by_region as ByRegionData[]} allRegions={allRegions} />;
  157. case 1:
  158. return <ByDateContent data={data?.by_date as ByDateData} allRegions={allRegions} />;
  159. default:
  160. return null;
  161. }
  162. };
  163. const handleImagePick = async () => {
  164. await refetchTemp().then(async (temp) => {
  165. if (temp.data?.photos && temp.data.photos.length > 0) {
  166. navigation.navigate(
  167. ...([
  168. NAVIGATION_PAGES.ADD_PHOTO,
  169. {
  170. data: null,
  171. images: [],
  172. allRegions: allRegions,
  173. tempData: temp.data.photos
  174. }
  175. ] as never)
  176. );
  177. } else {
  178. let result = await ImagePicker.launchImageLibraryAsync({
  179. mediaTypes: ImagePicker.MediaTypeOptions.Images,
  180. quality: 1,
  181. allowsMultipleSelection: true,
  182. exif: true
  183. });
  184. if (!result.canceled) {
  185. navigation.navigate(
  186. ...([
  187. NAVIGATION_PAGES.ADD_PHOTO,
  188. {
  189. data: null,
  190. images: result.assets,
  191. allRegions: allRegions
  192. }
  193. ] as never)
  194. );
  195. }
  196. }
  197. });
  198. };
  199. return (
  200. <PageWrapper>
  201. <Header label="Photos" />
  202. <View style={styles.buttonContainer}>
  203. <CustomButton
  204. title="By region"
  205. onPress={() => setContentIndex(0)}
  206. isActive={contentIndex === 0}
  207. />
  208. <CustomButton
  209. title="By date"
  210. onPress={() => setContentIndex(1)}
  211. isActive={contentIndex === 1}
  212. />
  213. <CustomButton
  214. title="Add"
  215. icon={<AddImgSvg fill={Colors.DARK_BLUE} />}
  216. onPress={handleImagePick}
  217. />
  218. </View>
  219. {renderContent()}
  220. </PageWrapper>
  221. );
  222. };
  223. export default PhotosScreen;