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 {AVATAR_PHOTO_ENDPOINT} from '../../constants'; import {UserType, PreviewType} from '../../types'; import {isUserBlocked} from '../../services'; import {useSelector, useDispatch, useStore} from 'react-redux'; import {RootState} from '../../store/rootreducer'; import {loadUserX, logout} from '../../store/actions'; import {userXInStore} from '../../utils'; const NO_USER: UserType = { userId: '', username: '', }; /** * This component returns user's profile picture followed 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 loadAvatar = async () => { try { const token = await AsyncStorage.getItem('token'); if (!token) { setUser(NO_USER); return; } const response = await RNFetchBlob.config({ fileCache: true, appendExt: 'jpg', }).fetch('GET', AVATAR_PHOTO_ENDPOINT + `${id}/`, { Authorization: 'Token ' + token, }); const status = response.info().status; if (status === 200) { if (mounted) { setAvatarURI(response.path()); } return; } if (mounted) { setAvatarURI(''); } } catch (error) { console.log(error); } }; loadAvatar(); 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 checkIfUserIsBlocked = async (userId: string) => { const token = await AsyncStorage.getItem('token'); if (!token) { dispatch(logout()); return false; } return await isUserBlocked(userId, loggedInUser.userId, token); }; const state: RootState = useStore().getState(); const addToRecentlyStoredAndNavigateToProfile = async () => { let user: ProfilePreviewType = { id, username, first_name, last_name, }; try { if (previewType !== 'Comment') { //If the logged in user is blocked by the user being viewed, do not proceed. const isUserBlocked = await checkIfUserIsBlocked(user.id); if (isUserBlocked) { Alert.alert('You cannot view this profile'); return; } 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)) { dispatch( loadUserX({userId: user.id, username: user.username}, screenType), ); } navigation.push('Profile', { username: user.username, userXId: user.id, screenType: 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; 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' && ( <> {first_name.concat(' ', last_name)} {usernameToDisplay} )} ); }; const styles = StyleSheet.create({ searchResultContainer: { flexDirection: 'row', alignItems: 'center', marginVertical: 10, }, commentContainer: { flexDirection: 'row', alignItems: 'center', }, discoverUsersContainer: { alignItems: 'center', textAlign: 'center', margin: '0.5%', width: '32%', marginVertical: 10, }, 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', }, 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', }, }); export default ProfilePreview;