import React, {useEffect, useState, useContext} from 'react'; import {ProfilePreviewType, ScreenType} from '../../types'; import { View, Text, Image, StyleSheet, ViewProps, TouchableOpacity, Alert, } from 'react-native'; import {useNavigation} from '@react-navigation/native'; import RNFetchBlob from 'rn-fetch-blob'; import AsyncStorage from '@react-native-community/async-storage'; import {PROFILE_PHOTO_THUMBNAIL_ENDPOINT} from '../../constants'; import {UserType, PreviewType} from '../../types'; import {isUserBlocked, loadAvatar} from '../../services'; import {useSelector, useDispatch, useStore} from 'react-redux'; import {RootState} from '../../store/rootreducer'; import {logout} from '../../store/actions'; import {checkIfUserIsBlocked, fetchUserX, userXInStore} from '../../utils'; import {SearchResultsBackground} from '../search'; import NavigationBar from 'src/routes/tabs'; const NO_USER: UserType = { userId: '', username: '', }; /** * This component returns user's profile picture friended by username as a touchable component. * What happens when someone clicks on this component is partly decided by the prop isComment. * If isComment is true then it means that we are not displaying this tile as a part of search results. * And hence we do not cache the search results. * On the other hand, if isComment is false, then we should update the search cache. (This cache needs to be revamped to clear outdated results.) * Finally, We navigate to Profile. */ interface ProfilePreviewProps extends ViewProps { profilePreview: ProfilePreviewType; previewType: PreviewType; screenType: ScreenType; } const ProfilePreview: React.FC = ({ profilePreview: {username, first_name, last_name, id}, previewType, screenType, }) => { const navigation = useNavigation(); const {user: loggedInUser} = useSelector((state: RootState) => state.user); const [avatarURI, setAvatarURI] = useState(null); const [user, setUser] = useState(NO_USER); const dispatch = useDispatch(); useEffect(() => { let mounted = true; const loadAvatarImage = async () => { const response = await loadAvatar(id, true); if (mounted) { setAvatarURI(response); } }; loadAvatarImage(); return () => { mounted = false; }; }, [id]); /** * Adds a searched user to the recently searched cache if they're tapped on. * Cache maintains 10 recently searched users, popping off the oldest one if * needed to make space. */ const state: RootState = useStore().getState(); const addToRecentlyStoredAndNavigateToProfile = async () => { let user: ProfilePreviewType = { id, username, first_name, last_name, }; try { //If the logged in user is blocked by the user being viewed, do not proceed. const isUserBlocked = await checkIfUserIsBlocked( user.id, dispatch, loggedInUser, ); if (isUserBlocked) { Alert.alert('You cannot view this profile'); return; } if (previewType !== 'Comment') { const jsonValue = await AsyncStorage.getItem( '@recently_searched_users', ); let recentlySearchedList = jsonValue != null ? JSON.parse(jsonValue) : null; if (recentlySearchedList) { if (recentlySearchedList.length > 0) { if ( recentlySearchedList.some( (saved_user: ProfilePreviewType) => saved_user.id === id, ) ) { console.log('User already in recently searched.'); } else { if (recentlySearchedList.length >= 10) { recentlySearchedList.pop(); } recentlySearchedList.unshift(user); } } } else { recentlySearchedList = [user]; } try { let recentlySearchedListString = JSON.stringify(recentlySearchedList); await AsyncStorage.setItem( '@recently_searched_users', recentlySearchedListString, ); } catch (e) { console.log(e); } } /** * Dispatch an event to Fetch the user details * If the user is already present in store, do not fetch again * Finally, Navigate to profile of the user selected */ if (!userXInStore(state, screenType, user.id)) { await fetchUserX( dispatch, {userId: user.id, username: user.username}, screenType, ); } const userXId = loggedInUser.username === user.username ? undefined : user.id; navigation.push('Profile', { userXId, screenType, }); } catch (e) { console.log(e); } }; var containerStyle, avatarStyle, nameContainerStyle, usernameToDisplay, usernameStyle, nameStyle; switch (previewType) { case 'Search' || 'Recent': containerStyle = styles.searchResultContainer; avatarStyle = styles.searchResultAvatar; nameContainerStyle = styles.searchResultNameContainer; usernameToDisplay = '@' + username; usernameStyle = styles.searchResultUsername; nameStyle = styles.searchResultName; break; case 'Discover Users': containerStyle = styles.discoverUsersContainer; avatarStyle = styles.discoverUsersAvatar; nameContainerStyle = styles.discoverUsersNameContainer; usernameToDisplay = '@' + username; usernameStyle = styles.discoverUsersUsername; nameStyle = styles.discoverUsersName; break; case 'Comment': containerStyle = styles.commentContainer; avatarStyle = styles.commentAvatar; nameContainerStyle = styles.commentNameContainer; usernameToDisplay = username; usernameStyle = styles.commentUsername; nameStyle = styles.commentName; break; case 'Friend': containerStyle = styles.friendContainer; avatarStyle = styles.friendAvatar; nameContainerStyle = styles.friendNameContainer; usernameToDisplay = '@' + username; usernameStyle = styles.friendUsername; nameStyle = styles.friendName; break; default: containerStyle = styles.searchResultContainer; avatarStyle = styles.searchResultAvatar; nameContainerStyle = styles.searchResultNameContainer; usernameToDisplay = '@' + username; usernameStyle = styles.searchResultUsername; nameStyle = styles.searchResultName; } return ( {(previewType === 'Search' || previewType === 'Recent') && ( <> {usernameToDisplay} {first_name.concat(' ', last_name)} )} {previewType === 'Comment' && ( {usernameToDisplay} )} {previewType === 'Discover Users' && ( <> {usernameToDisplay} )} {previewType === 'Friend' && ( <> {usernameToDisplay} {first_name.concat(' ', last_name)} )} ); }; const styles = StyleSheet.create({ searchResultContainer: { flexDirection: 'row', alignItems: 'center', marginVertical: 10, }, commentContainer: { flexDirection: 'row', alignItems: 'center', }, discoverUsersContainer: { alignItems: 'center', textAlign: 'center', width: '32%', marginVertical: 10, borderWidth: 1, }, searchResultAvatar: { height: 60, width: 60, borderRadius: 30, marginRight: 15, }, commentAvatar: { height: 40, width: 40, borderRadius: 20, marginRight: 15, marginTop: '2%', }, discoverUsersAvatar: { height: 60, width: 60, borderRadius: 30, }, searchResultNameContainer: { justifyContent: 'space-evenly', alignSelf: 'stretch', }, commentNameContainer: { justifyContent: 'space-evenly', alignSelf: 'stretch', }, discoverUsersNameContainer: { justifyContent: 'space-evenly', alignSelf: 'stretch', marginTop: 5, }, searchResultUsername: { fontSize: 18, fontWeight: '500', }, commentUsername: { fontSize: 16, fontWeight: '500', }, discoverUsersUsername: { fontSize: 14, fontWeight: '400', color: 'white', textAlign: 'center', }, searchResultName: { fontSize: 16, color: '#333', }, commentName: { fontSize: 16, color: '#333', }, discoverUsersName: { fontSize: 16, fontWeight: '700', color: 'white', textAlign: 'center', }, friendContainer: { flexDirection: 'row', alignItems: 'center', marginVertical: 10, }, friendAvatar: { height: 42, width: 42, marginRight: 15, borderRadius: 20, }, friendNameContainer: { justifyContent: 'space-evenly', alignSelf: 'stretch', }, friendUsername: { fontSize: 14, fontWeight: '700', color: '#3C3C3C', letterSpacing: 0.6, }, friendName: { fontSize: 12, fontWeight: '500', color: '#6C6C6C', letterSpacing: 0.5, }, }); export default ProfilePreview;