import {useFocusEffect, useNavigation} from '@react-navigation/native'; import React, {useCallback, useEffect, useState, useRef} from 'react'; import { FlatList, RefreshControl, StatusBar, StyleSheet, ViewToken, } from 'react-native'; import Animated from 'react-native-reanimated'; import {useDispatch, useSelector, useStore} from 'react-redux'; import {TabsGradient, TaggLoadingIndicator, Background} from '../../components'; import {SP_PAGE_SIZE} from '../../constants'; import SuggestedPeopleOnboardingStackScreen from '../../routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen'; import {getSuggestedPeople} from '../../services/SuggestedPeopleService'; import {cancelFriendRequest, resetScreenType} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; import { FriendshipStatusType, ProfilePreviewType, ScreenType, SuggestedPeopleDataType, BackgroundGradientType, } from '../../types'; import { fetchUserX, getUserAsProfilePreviewType, handleAddFriend, normalize, SCREEN_HEIGHT, SCREEN_WIDTH, } from '../../utils'; import {userXInStore} from './../../utils/'; import SPBody from './SPBody'; /** * Bare bones for suggested people consisting of: * * Image, title, name, username, add friend button [w/o functionality] */ const SuggestedPeopleScreen: React.FC = () => { const y = Animated.useValue(0); const navigation = useNavigation(); const state: RootState = useStore().getState(); const dispatch = useDispatch(); const screenType = ScreenType.SuggestedPeople; const {suggested_people_linked} = useSelector( (state: RootState) => state.user.profile, ) ?? {suggested_people_linked: -1}; const {userId: loggedInUserId} = useSelector( (state: RootState) => state.user.user, ); const {suggestedPeopleImage} = useSelector((state: RootState) => state.user); const [people, setPeople] = useState([]); const [displayedUser, setDisplayedUser] = useState(); const [page, setPage] = useState(0); const [refreshing, setRefreshing] = useState(false); const [shouldResetData, setShouldResetData] = useState(false); const [hideStatusBar, setHideStatusBar] = useState(false); // boolean for showing/hiding loading indicator const [loading, setLoading] = useState(true); // set loading to false once there are people to display useEffect(() => { people.length ? setLoading(false) : setLoading(true); }, [people]); const stausBarRef = useRef(hideStatusBar); // loads data and append it to users based on current page useEffect(() => { loadMore(); }, [page]); useEffect(() => { if (shouldResetData) { if (page !== 0) { setPage(0); } else { loadMore(); } } }, [shouldResetData]); useEffect(() => { const appendSelf = async () => { const self = { user: getUserAsProfilePreviewType(state.user.user, state.user.profile), mutual_friends: [], badges: [], social_links: [], suggested_people_url: suggestedPeopleImage, }; people.unshift(self); setPeople(people); }; if (suggested_people_linked < 2) { if (people.length > 1 && people[0].user.id !== loggedInUserId) { appendSelf(); } } }, [suggestedPeopleImage]); const loadMore = async () => { const loadNextPage = async () => await getSuggestedPeople( SP_PAGE_SIZE, shouldResetData ? 0 : page * SP_PAGE_SIZE, ); loadNextPage().then((newUsers) => { loadUserDataToStore(newUsers.map((ppl) => ppl.user)); if (shouldResetData) { setPeople([]); } setPeople(shouldResetData ? newUsers : people.concat(newUsers)); setShouldResetData(false); }); }; const loadUserDataToStore = async (users: ProfilePreviewType[]) => { const loadUserData = async (user: ProfilePreviewType) => { if (!userXInStore(state, screenType, user.id)) { await fetchUserX( dispatch, {userId: user.id, username: user.username}, screenType, ); } }; await Promise.all(users.map((user) => loadUserData(user))); }; const onRefresh = () => { const reset = async () => { await dispatch(resetScreenType(screenType)); setShouldResetData(true); }; setRefreshing(true); reset().then(() => { setRefreshing(false); }); }; useFocusEffect( useCallback(() => { const navigateToAnimatedTutorial = () => { // if the user has finished the previous SP onboarding if (suggested_people_linked === 1) { navigation.navigate('AnimatedTutorial'); } }; navigateToAnimatedTutorial(); StatusBar.setHidden(stausBarRef.current); StatusBar.setBarStyle('light-content'); return () => { StatusBar.setHidden(false); StatusBar.setBarStyle('dark-content'); }; }, [navigation, suggested_people_linked]), ); const updateDisplayedUser = async ( user: ProfilePreviewType, status: FriendshipStatusType, requester_id: string, ) => { const localDisplayedUser: SuggestedPeopleDataType = { ...displayedUser, friendship: {status, requester_id}, }; setDisplayedUser(localDisplayedUser); setPeople( people.map((item) => { if (item.user.id === user.id) { item.friendship.status = status; item.friendship.requester_id = requester_id; } return item; }), ); }; const onAddFriend = async (user: ProfilePreviewType) => { handleAddFriend(screenType, user, dispatch, state); updateDisplayedUser(user, 'requested', loggedInUserId); }; const onCancelRequest = (user: ProfilePreviewType) => { dispatch(cancelFriendRequest(user.id)); updateDisplayedUser(user, 'no_record', ''); }; const onViewableItemsChanged = useCallback( ({viewableItems}: {viewableItems: ViewToken[]}) => { setHideStatusBar(viewableItems[0].index !== 0); stausBarRef.current = viewableItems[0].index !== 0; }, [], ); return suggested_people_linked === 0 ? ( ) : loading ? ( <> ) : ( <> { return ( ); }} keyExtractor={(item, index) => index.toString()} showsVerticalScrollIndicator={false} onViewableItemsChanged={onViewableItemsChanged} onEndReached={() => setPage(page + 1)} refreshControl={ } pagingEnabled /> ); }; const styles = StyleSheet.create({ mainContainer: { flexDirection: 'column', width: SCREEN_WIDTH, height: SCREEN_HEIGHT, paddingVertical: '15%', paddingBottom: '20%', justifyContent: 'space-between', alignSelf: 'center', }, marginManager: {marginHorizontal: '5%'}, image: { position: 'absolute', width: SCREEN_WIDTH, height: SCREEN_HEIGHT, zIndex: 0, }, title: { zIndex: 1, paddingTop: '3%', alignSelf: 'center', fontSize: normalize(22), lineHeight: normalize(26), fontWeight: '800', letterSpacing: normalize(3), color: '#FFFEFE', textShadowColor: 'rgba(0, 0, 0, 0.4)', textShadowOffset: {width: normalize(2), height: normalize(2)}, textShadowRadius: normalize(2), }, firstName: { color: '#fff', fontWeight: '800', fontSize: normalize(24), lineHeight: normalize(29), textShadowColor: 'rgba(0, 0, 0, 0.3)', textShadowOffset: {width: normalize(2), height: normalize(2)}, textShadowRadius: normalize(2), letterSpacing: normalize(2.5), alignSelf: 'baseline', }, username: { color: '#fff', fontWeight: '600', fontSize: normalize(15), lineHeight: normalize(18), textShadowColor: 'rgba(0, 0, 0, 0.3)', textShadowOffset: {width: normalize(2), height: normalize(2)}, textShadowRadius: normalize(2), letterSpacing: normalize(2), }, nameInfoContainer: {}, addButton: { justifyContent: 'center', alignItems: 'center', width: SCREEN_WIDTH * 0.3, height: SCREEN_WIDTH * 0.085, padding: 0, borderWidth: 2, borderColor: '#fff', borderRadius: 1, marginLeft: '1%', marginTop: '4%', shadowColor: 'rgb(0, 0, 0)', shadowRadius: 2, shadowOffset: {width: 2, height: 2}, shadowOpacity: 0.5, }, addButtonTitle: { color: 'white', padding: 0, fontSize: normalize(15), lineHeight: normalize(18), fontWeight: 'bold', textAlign: 'center', letterSpacing: normalize(1), }, addUserContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '5%', }, requestedButton: { justifyContent: 'center', alignItems: 'center', width: SCREEN_WIDTH * 0.3, height: SCREEN_WIDTH * 0.085, padding: 0, borderWidth: 2, borderColor: 'transparent', borderRadius: 1, marginLeft: '1%', marginTop: '4%', shadowColor: 'rgb(0, 0, 0)', shadowRadius: 2, shadowOffset: {width: 2, height: 2}, shadowOpacity: 0.5, }, requestedButtonTitle: { backgroundColor: 'transparent', fontSize: normalize(15), lineHeight: normalize(18), fontWeight: 'bold', textAlign: 'center', letterSpacing: normalize(1), }, body: {}, button: { justifyContent: 'center', alignItems: 'center', width: SCREEN_WIDTH * 0.4, aspectRatio: 154 / 33, borderWidth: 2, borderColor: '#fff', borderRadius: 3, marginRight: '2%', marginLeft: '1%', }, transparentBG: { backgroundColor: 'transparent', }, lightBlueBG: { backgroundColor: '#fff', }, label: { fontSize: normalize(15), fontWeight: '700', letterSpacing: 1, }, blueLabel: { color: '#fff', }, whiteLabel: { color: 'white', }, }); export default SuggestedPeopleScreen;