123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
- import { View, Image, Text, TouchableOpacity } from 'react-native';
- import { useNavigation } from '@react-navigation/native';
- import * as Progress from 'react-native-progress';
- import { getImageUri, photoStyles, smallPhotoHeight, smallPhotoWidth } from '../../utils';
- import { NAVIGATION_PAGES } from 'src/types';
- import { styles } from '../../Components/styles';
- import { API_HOST } from 'src/constants';
- import ImageView from 'better-react-native-image-viewing';
- import { EventPhotos } from '@api/events';
- import { ImageSource } from 'expo-image';
- import { Colors } from 'src/theme';
- type Photo = {
- id: number;
- filetype: string;
- data: 0 | 1;
- preview: 0 | 1;
- uid: number;
- name: string;
- avatar: string | null;
- uri: string;
- isSending?: boolean;
- };
- export const PhotoItem = React.memo(
- ({ photos, eventId, photosLeft }: { photos: any; eventId: number; photosLeft: number }) => {
- const navigation = useNavigation();
- const [currentImageIndex, setCurrentImageIndex] = useState(0);
- const [isViewerVisible, setIsViewerVisible] = useState(false);
- const [fullImages, setFullImages] = useState<EventPhotos[]>([]);
- const openImageViewer = (index: number) => {
- setCurrentImageIndex(index);
- setIsViewerVisible(true);
- };
- useEffect(() => {
- setFullImages(
- photos
- .filter((p: EventPhotos) => p.data)
- .map((photo: Photo) => ({
- ...photo,
- uri: API_HOST + '/webapi/events/get-photo/' + eventId + '/' + photo.id
- }))
- );
- }, [photos]);
- const renderSpinner = (style: any) => (
- <View
- style={[
- style,
- {
- alignItems: 'center',
- justifyContent: 'center',
- backgroundColor: Colors.FILL_LIGHT
- }
- ]}
- >
- <Progress.CircleSnail
- borderWidth={0}
- color={Colors.DARK_BLUE}
- unfilledColor="rgba(0, 0, 0, 0.1)"
- />
- </View>
- );
- const renderPhotos = () => {
- const photosToShow = photos.filter((p: EventPhotos) => p.preview).slice(0, 3);
- const morePhotosCount = photos.length - 3 + photosLeft;
- if (photosToShow.length === 1) {
- return (
- <TouchableOpacity onPress={() => openImageViewer(0)}>
- {photosToShow[0].isSending ? (
- renderSpinner(photoStyles.onePhoto)
- ) : (
- <Image
- source={{
- uri: getImageUri(
- '/webapi/events/get-photo-preview/' + eventId + '/' + photosToShow[0].id
- )
- }}
- style={photoStyles.onePhoto}
- />
- )}
- </TouchableOpacity>
- );
- } else if (photosToShow.length === 2) {
- return photosToShow.map((photo: Photo, index: number) => (
- <TouchableOpacity key={photo.id} onPress={() => openImageViewer(index)}>
- {photo?.isSending ? (
- renderSpinner({ ...photoStyles.twoPhotos, marginRight: index === 0 ? 8 : 0 })
- ) : (
- <Image
- source={{
- uri: getImageUri(
- '/webapi/events/get-photo-preview/' + eventId + '/' + photosToShow.id
- )
- }}
- style={[photoStyles.twoPhotos, index === 0 && { marginRight: 8 }]}
- />
- )}
- </TouchableOpacity>
- ));
- } else {
- return (
- <View style={{ flexDirection: 'row' }}>
- <TouchableOpacity onPress={() => openImageViewer(0)}>
- {photosToShow[0].isSending ? (
- renderSpinner(photoStyles.bigPhoto)
- ) : (
- <Image
- source={{
- uri: getImageUri(
- '/webapi/events/get-photo-preview/' + eventId + '/' + photosToShow[0].id
- )
- }}
- style={photoStyles.bigPhoto}
- />
- )}
- </TouchableOpacity>
- <View style={styles.smallPhotoContainer}>
- <TouchableOpacity onPress={() => openImageViewer(1)}>
- {photosToShow[1].isSending ? (
- renderSpinner(photoStyles.smallPhoto)
- ) : (
- <Image
- source={{
- uri: getImageUri(
- '/webapi/events/get-photo-preview/' + eventId + '/' + photosToShow[1].id
- )
- }}
- style={photoStyles.smallPhoto}
- />
- )}
- </TouchableOpacity>
- <TouchableOpacity onPress={() => openImageViewer(2)}>
- <Image
- source={{
- uri: getImageUri(
- '/webapi/events/get-photo-preview/' + eventId + '/' + photosToShow[2].id
- )
- }}
- style={[photoStyles.smallPhoto, { position: 'relative' }]}
- />
- </TouchableOpacity>
- {morePhotosCount > 0 && (
- <TouchableOpacity
- onPress={() => handlePress()}
- style={[
- styles.morePhotosOverlay,
- { width: smallPhotoWidth, height: smallPhotoHeight }
- ]}
- >
- <Text style={styles.morePhotosText}>+{morePhotosCount}</Text>
- </TouchableOpacity>
- )}
- </View>
- </View>
- );
- }
- };
- const photoViews = useMemo(() => renderPhotos(), [photos]);
- const handlePress = useCallback(() => {
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.ALL_EVENT_PHOTOS,
- {
- data: photos,
- eventId,
- lastPhotoId: photos[photos.length - 1].id,
- photosCountLeft: photosLeft
- }
- ] as never)
- );
- }, [navigation, photos]);
- return (
- <View>
- {photoViews}
- <ImageView
- images={fullImages as ImageSource[]}
- keyExtractor={(imageSrc, index) => index.toString()}
- imageIndex={currentImageIndex}
- visible={isViewerVisible}
- onRequestClose={() => setIsViewerVisible(false)}
- swipeToCloseEnabled={false}
- backgroundColor={Colors.DARK_BLUE}
- FooterComponent={({ imageIndex }) => (
- <View style={styles.imageFooter}>
- <TouchableOpacity
- onPress={() => {
- setIsViewerVisible(false);
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW,
- { userId: fullImages[imageIndex].uid }
- ] as never)
- );
- }}
- disabled={!fullImages[imageIndex].uid}
- style={styles.imageOwner}
- >
- {fullImages[imageIndex].avatar ? (
- <Image
- source={{ uri: API_HOST + fullImages[imageIndex].avatar }}
- style={{
- width: 28,
- height: 28,
- borderRadius: 14
- }}
- />
- ) : null}
- <Text style={styles.imageOwnerText}>{fullImages[imageIndex].name}</Text>
- </TouchableOpacity>
- </View>
- )}
- />
- </View>
- );
- }
- );
|