diff options
Diffstat (limited to 'src/components/moments/MomentPost.tsx')
-rw-r--r-- | src/components/moments/MomentPost.tsx | 347 |
1 files changed, 311 insertions, 36 deletions
diff --git a/src/components/moments/MomentPost.tsx b/src/components/moments/MomentPost.tsx index d87028e3..6eccf5ab 100644 --- a/src/components/moments/MomentPost.tsx +++ b/src/components/moments/MomentPost.tsx @@ -1,38 +1,77 @@ -import React, {useEffect, useState} from 'react'; -import {StyleSheet} from 'react-native'; -import {useSelector} from 'react-redux'; -import {MomentPostContent, MomentPostHeader} from '.'; +import {useNavigation} from '@react-navigation/native'; +import React, {useContext, useEffect, useRef, useState} from 'react'; +import { + Image, + KeyboardAvoidingView, + Platform, + StatusBar, + StyleSheet, + Text, + TouchableOpacity, + TouchableWithoutFeedback, + View, +} from 'react-native'; +import Animated, {EasingNode} from 'react-native-reanimated'; +import {useDispatch, useSelector, useStore} from 'react-redux'; +import {headerBarOptions} from '../../routes'; +import {MomentContext} from '../../screens/profile/IndividualMoment'; import {deleteMomentTag, loadMomentTags} from '../../services'; +import {loadUserMoments} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; -import {MomentPostType, MomentTagType, ScreenType} from '../../types'; -import {normalize, SCREEN_HEIGHT} from '../../utils'; - +import {MomentPostType, MomentTagType, ScreenType, UserType} from '../../types'; +import { + getTimePosted, + HeaderHeight, + isIPhoneX, + navigateToProfile, + normalize, + SCREEN_HEIGHT, + SCREEN_WIDTH, +} from '../../utils'; +import {mentionPartTypes, renderTextWithMentions} from '../../utils/comments'; +import {AddComment} from '../comments'; +import CommentsCount from '../comments/CommentsCount'; +import {MomentTags} from '../common'; +import {MomentMoreInfoDrawer, TaggAvatar} from '../profile'; +import IndividualMomentTitleBar from './IndividualMomentTitleBar'; interface MomentPostProps { moment: MomentPostType; userXId: string | undefined; screenType: ScreenType; - index: number; } const MomentPost: React.FC<MomentPostProps> = ({ moment, userXId, screenType, - index, }) => { + const navigation = useNavigation(); + const dispatch = useDispatch(); const {userId: loggedInUserId, username: loggedInUsername} = useSelector( (state: RootState) => state.user.user, ); - - const { - user: {username}, - } = useSelector((state: RootState) => + const {user} = useSelector((state: RootState) => userXId ? state.userX[screenType][userXId] : state.user, ); + const state: RootState = useStore().getState(); + const isOwnProfile = user.username === loggedInUsername; + const [tags, setTags] = useState<MomentTagType[]>([]); + const [visible, setVisible] = useState(false); + const [drawerVisible, setDrawerVisible] = useState(false); + const [hideText, setHideText] = useState(false); + + const [fadeValue, setFadeValue] = useState<Animated.Value<number>>( + new Animated.Value(0), + ); + const [commentCount, setCommentCount] = useState<number>( + moment.comments_count, + ); + const [aspectRatio, setAspectRatio] = useState<number>(1); const [momentTagId, setMomentTagId] = useState<string>(''); - const isOwnProfile = username === loggedInUsername; + const imageRef = useRef(null); + const {keyboardVisible} = useContext(MomentContext); /* * Load tags on initial render to pass tags data to moment header and content @@ -41,7 +80,7 @@ const MomentPost: React.FC<MomentPostProps> = ({ loadMomentTags(moment.moment_id).then((response) => { setTags(response ? response : []); }); - }, []); + }, [moment]); /* * Check if loggedInUser has been tagged in the picture and set the id @@ -71,34 +110,270 @@ const MomentPost: React.FC<MomentPostProps> = ({ } }; + useEffect( + () => + navigation.setOptions({ + ...headerBarOptions('white', ''), + headerTitle: () => ( + <IndividualMomentTitleBar title={moment.moment_category} /> + ), + }), + [moment.moment_id], + ); + + /* + * Determines if an image is 9:16 to set aspect ratio of current image and + * determine if image must be displayed in full screen or not + */ + useEffect(() => { + Image.getSize( + moment.moment_url, + (w, h) => { + setAspectRatio(w / h); + }, + (err) => console.log(err), + ); + }, []); + + /* + * To animate tags display + */ + useEffect(() => { + const fade = async () => { + Animated.timing(fadeValue, { + toValue: 1, + duration: 250, + easing: EasingNode.linear, + }).start(); + }; + fade(); + }, [fadeValue]); + + useEffect(() => { + if (!keyboardVisible && hideText) { + setHideText(false); + } + }, [keyboardVisible, hideText]); + + const MomentPosterPreview = () => ( + <View style={styles.momentPosterContainer}> + <TouchableOpacity + onPress={() => + navigateToProfile(state, dispatch, navigation, screenType, user) + } + style={styles.header}> + <TaggAvatar + style={styles.avatar} + userXId={userXId} + screenType={screenType} + editable={false} + /> + <Text style={styles.headerText}>{user.username}</Text> + </TouchableOpacity> + </View> + ); + return ( <> - <MomentPostHeader - style={styles.postHeader} - userXId={userXId} - screenType={screenType} - username={isOwnProfile ? loggedInUsername : username} - momentTagId={momentTagId} - removeTag={removeTag} - moment={moment} - tags={tags} - /> - <MomentPostContent - style={styles.postContent} - moment={moment} - screenType={screenType} - momentTags={tags} - index={index} - /> + <StatusBar barStyle={'light-content'} /> + <View style={styles.mainContainer}> + <View style={styles.imageContainer}> + <Image + source={{uri: moment.moment_url}} + style={[ + styles.image, + { + height: SCREEN_WIDTH / aspectRatio, + }, + ]} + resizeMode={'contain'} + ref={imageRef} + /> + </View> + {visible && ( + <Animated.View style={[styles.tagsContainer, {opacity: fadeValue}]}> + <MomentTags + editing={false} + tags={tags} + setTags={() => null} + imageRef={imageRef} + /> + </Animated.View> + )} + <TouchableWithoutFeedback + onPress={() => { + setVisible(!visible); + setFadeValue(new Animated.Value(0)); + }}> + <View style={styles.contentContainer}> + <View style={styles.topContainer}> + <MomentMoreInfoDrawer + isOpen={drawerVisible} + setIsOpen={setDrawerVisible} + isOwnProfile={isOwnProfile} + momentTagId={momentTagId} + removeTag={removeTag} + dismissScreenAndUpdate={() => { + dispatch(loadUserMoments(loggedInUserId)); + navigation.goBack(); + }} + screenType={screenType} + moment={moment} + tags={tags} + /> + </View> + <KeyboardAvoidingView + behavior={Platform.OS === 'ios' ? 'padding' : 'height'} + keyboardVerticalOffset={-20}> + <View style={styles.bottomContainer}> + {tags.length > 0 && ( + <Image + source={require('../../assets/icons/tag_indicate.png')} + style={styles.tagIcon} + /> + )} + <View style={styles.commentsCountContainer}> + <CommentsCount moment={moment} screenType={screenType} /> + </View> + <MomentPosterPreview /> + {!hideText && ( + <> + {moment.caption !== '' && + renderTextWithMentions({ + value: moment.caption, + styles: styles.captionText, + partTypes: mentionPartTypes('white', 'caption'), + onPress: (userLocal: UserType) => + navigateToProfile( + state, + dispatch, + navigation, + screenType, + userLocal, + ), + })} + </> + )} + <View> + <AddComment + placeholderText={'Add a comment here!'} + momentId={moment.moment_id} + callback={() => { + setCommentCount(commentCount + 1); + }} + onFocus={() => { + setHideText(true); + }} + isKeyboardAvoiding={false} + theme={'dark'} + /> + <Text style={styles.text}> + {getTimePosted(moment.date_created)} + </Text> + </View> + </View> + </KeyboardAvoidingView> + </View> + </TouchableWithoutFeedback> + </View> </> ); }; const styles = StyleSheet.create({ - postHeader: {}, - postContent: { - minHeight: SCREEN_HEIGHT * 0.8, - paddingBottom: normalize(20), + image: { + zIndex: 0, + }, + imageContainer: { + height: SCREEN_HEIGHT, + width: SCREEN_WIDTH, + flexDirection: 'column', + justifyContent: 'center', + overflow: 'hidden', + }, + text: { + marginHorizontal: '5%', + color: 'white', + fontWeight: '500', + textAlign: 'right', + marginTop: 5, + }, + captionText: { + position: 'relative', + marginHorizontal: '5%', + color: '#ffffff', + fontWeight: '500', + fontSize: normalize(13), + lineHeight: normalize(15.51), + letterSpacing: normalize(0.6), + marginBottom: normalize(5), + width: SCREEN_WIDTH * 0.79, + }, + tagIcon: { + width: normalize(30), + height: normalize(30), + bottom: normalize(20), + left: '5%', + }, + avatar: { + width: 48, + aspectRatio: 1, + borderRadius: 100, + marginLeft: '3%', + }, + headerText: { + fontSize: 15, + fontWeight: 'bold', + color: 'white', + paddingHorizontal: '3%', + }, + header: { + alignItems: 'center', + flexDirection: 'row', + marginBottom: normalize(15), + alignSelf: 'flex-start', + }, + momentPosterContainer: { + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + }, + commentsCountContainer: { + position: 'absolute', + right: '2%', + bottom: SCREEN_HEIGHT * 0.12, + }, + bottomContainer: { + flexDirection: 'column', + justifyContent: 'flex-end', + }, + topContainer: { + paddingTop: isIPhoneX() ? HeaderHeight : '6%', + alignSelf: 'flex-end', + paddingRight: '8%', + }, + contentContainer: { + position: 'absolute', + width: SCREEN_WIDTH, + height: SCREEN_HEIGHT, + flexDirection: 'column', + justifyContent: 'space-between', + paddingBottom: '24%', + }, + tagsContainer: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + marginBottom: '3%', + }, + mainContainer: { + backgroundColor: 'black', + width: SCREEN_WIDTH, + height: SCREEN_HEIGHT, + flexDirection: 'column', + justifyContent: 'center', }, }); |