diff options
Diffstat (limited to 'src/screens')
| -rw-r--r-- | src/screens/chat/ChatListScreen.tsx | 90 | ||||
| -rw-r--r-- | src/screens/chat/ChatScreen.tsx | 36 | ||||
| -rw-r--r-- | src/screens/onboarding/Login.tsx | 1 | ||||
| -rw-r--r-- | src/screens/profile/ProfileScreen.tsx | 28 | ||||
| -rw-r--r-- | src/screens/profile/SettingsScreen.tsx | 6 | ||||
| -rw-r--r-- | src/screens/search/DiscoverUsers.tsx | 2 | ||||
| -rw-r--r-- | src/screens/search/SearchScreen.tsx | 180 | ||||
| -rw-r--r-- | src/screens/suggestedPeople/SPBody.tsx | 20 | ||||
| -rw-r--r-- | src/screens/suggestedPeople/SuggestedPeopleScreen.tsx | 2 |
9 files changed, 170 insertions, 195 deletions
diff --git a/src/screens/chat/ChatListScreen.tsx b/src/screens/chat/ChatListScreen.tsx index c49c790d..9011ed4a 100644 --- a/src/screens/chat/ChatListScreen.tsx +++ b/src/screens/chat/ChatListScreen.tsx @@ -1,8 +1,13 @@ -import React from 'react'; -import {View, StyleSheet, Text, TouchableOpacity} from 'react-native'; +import AsyncStorage from '@react-native-community/async-storage'; import {StackNavigationProp} from '@react-navigation/stack'; - +import React, {useContext, useEffect, useMemo, useState} from 'react'; +import {SafeAreaView, StatusBar, StyleSheet, View} from 'react-native'; +import {useStore} from 'react-redux'; +import {ChannelList, Chat} from 'stream-chat-react-native'; +import {ChatContext} from '../../App'; +import {MessagesHeader} from '../../components/messages'; import {MainStackParams} from '../../routes'; +import {RootState} from '../../store/rootReducer'; type ChatListScreenNavigationProp = StackNavigationProp< MainStackParams, @@ -15,19 +20,80 @@ interface ChatListScreenProps { * Screen that displays all of the user's active conversations. */ const ChatListScreen: React.FC<ChatListScreenProps> = ({navigation}) => { + const {chatClient, setChannel} = useContext(ChatContext); + const [clientReady, setClientReady] = useState(false); + const state: RootState = useStore().getState(); + const loggedInUserId = state.user.user.userId; + + const memoizedFilters = useMemo( + () => ({ + members: {$in: [loggedInUserId]}, + type: 'messaging', + }), + [], + ); + + useEffect(() => { + const setupClient = async () => { + const chatToken = await AsyncStorage.getItem('chatToken'); + await chatClient.connectUser( + { + id: loggedInUserId, + }, + chatToken, + ); + return setClientReady(true); + }; + if (!clientReady) { + setupClient().catch((err) => { + console.error(err); + }); + } + }, []); + return ( - <View style={styles.container}> - <Text style={styles.placeholder}>I am the chat list.</Text> - <TouchableOpacity - style={styles.button} - onPress={() => navigation.navigate('Chat')}> - <Text>Let's go to a conversation!</Text> - </TouchableOpacity> + <View style={styles.background}> + <SafeAreaView> + <StatusBar barStyle="dark-content" /> + <MessagesHeader + createChannel={() => { + // TODO: (CHAT) change me + const channel = chatClient.channel('messaging', { + name: 'Awesome channel with foobar', + members: [loggedInUserId, 'd5295557-59ce-49fc-aa8a-442874dbffc3'], + }); + channel.create(); + }} + /> + {clientReady && ( + <Chat client={chatClient}> + <View style={styles.chatContainer}> + <ChannelList + filters={memoizedFilters} + onSelect={(channel) => { + setChannel(channel); + navigation.navigate('Chat'); + }} + options={{ + presence: true, + state: true, + watch: true, + }} + sort={{last_message_at: -1}} + /> + </View> + </Chat> + )} + </SafeAreaView> </View> ); }; const styles = StyleSheet.create({ + background: { + flex: 1, + backgroundColor: 'white', + }, container: { flex: 1, justifyContent: 'center', @@ -43,6 +109,10 @@ const styles = StyleSheet.create({ padding: 15, borderRadius: 5, }, + chatContainer: { + height: '100%', + marginTop: 10, + }, }); export default ChatListScreen; diff --git a/src/screens/chat/ChatScreen.tsx b/src/screens/chat/ChatScreen.tsx index af83f504..eeb1a7d6 100644 --- a/src/screens/chat/ChatScreen.tsx +++ b/src/screens/chat/ChatScreen.tsx @@ -1,7 +1,14 @@ -import React from 'react'; -import {View, StyleSheet, Text} from 'react-native'; -import {StackNavigationProp} from '@react-navigation/stack'; - +import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs'; +import {StackNavigationProp, useHeaderHeight} from '@react-navigation/stack'; +import React, {useContext} from 'react'; +import {StyleSheet, View} from 'react-native'; +import { + Channel, + Chat, + MessageInput, + MessageList, +} from 'stream-chat-react-native'; +import {ChatContext} from '../../App'; import {MainStackParams} from '../../routes'; type ChatScreenNavigationProp = StackNavigationProp<MainStackParams, 'Chat'>; @@ -12,22 +19,25 @@ interface ChatScreenProps { * Screen that displays all of the user's active conversations. */ const ChatScreen: React.FC<ChatScreenProps> = () => { + const {channel, chatClient} = useContext(ChatContext); + const headerHeight = useHeaderHeight(); + const tabbarHeight = useBottomTabBarHeight(); + return ( - <View style={styles.container}> - <Text style={styles.placeholder}>I am a chat!</Text> + <View style={[styles.container, {paddingBottom: tabbarHeight}]}> + <Chat client={chatClient}> + <Channel channel={channel} keyboardVerticalOffset={headerHeight}> + <MessageList onThreadSelect={() => {}} /> + <MessageInput /> + </Channel> + </Chat> </View> ); }; const styles = StyleSheet.create({ container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - placeholder: { - fontSize: 14, - fontWeight: 'bold', + backgroundColor: 'white', }, }); diff --git a/src/screens/onboarding/Login.tsx b/src/screens/onboarding/Login.tsx index 49ca5ff4..dd2bb2e4 100644 --- a/src/screens/onboarding/Login.tsx +++ b/src/screens/onboarding/Login.tsx @@ -160,6 +160,7 @@ const Login: React.FC<LoginProps> = ({navigation}: LoginProps) => { await AsyncStorage.setItem('token', data.token); await AsyncStorage.setItem('userId', data.UserID); await AsyncStorage.setItem('username', username); + await AsyncStorage.setItem('chatToken', data.chatToken); } if (statusCode === 200 && data.isOnboarded) { diff --git a/src/screens/profile/ProfileScreen.tsx b/src/screens/profile/ProfileScreen.tsx index 0d6af21e..6d9ef020 100644 --- a/src/screens/profile/ProfileScreen.tsx +++ b/src/screens/profile/ProfileScreen.tsx @@ -1,15 +1,9 @@ import React from 'react'; import {StatusBar} from 'react-native'; -import Animated from 'react-native-reanimated'; import {Content, TabsGradient} from '../../components'; import {RouteProp} from '@react-navigation/native'; import {MainStackParams} from '../../routes/'; -/**r - * Profile Screen for a user's profile - * including posts, messaging, and settings - */ - type ProfileScreenRouteProps = RouteProp<MainStackParams, 'Profile'>; interface ProfileOnboardingProps { @@ -19,31 +13,11 @@ interface ProfileOnboardingProps { const ProfileScreen: React.FC<ProfileOnboardingProps> = ({route}) => { const {screenType} = route.params; let {userXId} = route.params; - const y = Animated.useValue(0); - - /** - * This is a double safety check to avoid app crash. - * Checks if the required userXId is present in the store, if not userXId is set to dummy id - */ - // if (userXId && !(userXId in useStore().getState().userX[screenType])) { - // userXId = DUMMY_USERID; - // } - - /** - * Code under useFocusEffect gets executed every time the screen comes under focus / is being viewed by the user. - * This is done to reset the users stored in our store for the Search screen. - * Read more about useFocusEffect here : https://reactnavigation.org/docs/function-after-focusing-screen/ - */ - // useFocusEffect(() => { - // if (!userXId) { - // dispatch(resetScreenType(screenType)); - // } - // }); return ( <> <StatusBar barStyle="dark-content" /> - <Content {...{y, userXId, screenType}} /> + <Content {...{userXId, screenType}} /> <TabsGradient /> </> ); diff --git a/src/screens/profile/SettingsScreen.tsx b/src/screens/profile/SettingsScreen.tsx index 05e051b5..ecc3bafd 100644 --- a/src/screens/profile/SettingsScreen.tsx +++ b/src/screens/profile/SettingsScreen.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useContext} from 'react'; import { SafeAreaView, SectionList, @@ -17,6 +17,7 @@ import {BackgroundGradientType} from '../../types'; import {normalize, SCREEN_HEIGHT} from '../../utils/layouts'; import SettingsCell from './SettingsCell'; import {useNavigation} from '@react-navigation/core'; +import {ChatContext} from '../../App'; const SettingsScreen: React.FC = () => { const dispatch = useDispatch(); @@ -24,6 +25,7 @@ const SettingsScreen: React.FC = () => { const {suggested_people_linked} = useSelector( (state: RootState) => state.user.profile, ); + const {chatClient} = useContext(ChatContext); return ( <> @@ -49,7 +51,7 @@ const SettingsScreen: React.FC = () => { <TouchableOpacity style={styles.logoutContainerStyles} onPress={() => { - dispatch(logout()); + dispatch(logout(chatClient)); navigation.reset({ index: 0, routes: [{name: 'SuggestedPeople'}], diff --git a/src/screens/search/DiscoverUsers.tsx b/src/screens/search/DiscoverUsers.tsx index b87bfc37..f67585f2 100644 --- a/src/screens/search/DiscoverUsers.tsx +++ b/src/screens/search/DiscoverUsers.tsx @@ -126,7 +126,7 @@ const DiscoverUsers: React.FC<DiscoverUsersProps> = ({route}) => { ListFooterComponent={() => ( <> <Text style={styles.otherGroups}>Other Groups</Text> - <SearchCategories darkStyle={true} /> + <SearchCategories useSuggestions={true} darkStyle={true} /> </> )} /> diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx index 4f0cabb4..f7e1c467 100644 --- a/src/screens/search/SearchScreen.tsx +++ b/src/screens/search/SearchScreen.tsx @@ -1,8 +1,19 @@ import AsyncStorage from '@react-native-community/async-storage'; import {useFocusEffect} from '@react-navigation/native'; import React, {useEffect, useState} from 'react'; -import {Keyboard, ScrollView, StatusBar, StyleSheet} from 'react-native'; -import Animated, {Easing, timing} from 'react-native-reanimated'; +import { + Keyboard, + StatusBar, + StyleSheet, + LayoutChangeEvent, + SectionListData, +} from 'react-native'; +import { + useSharedValue, + withTiming, + Easing, + runOnJS, +} from 'react-native-reanimated'; import {SafeAreaView} from 'react-native-safe-area-context'; import {useDispatch, useSelector} from 'react-redux'; import { @@ -13,22 +24,14 @@ import { SearchResultsBackground, TabsGradient, } from '../../components'; -import {SEARCH_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants'; +import {SEARCH_ENDPOINT} from '../../constants'; import {loadSearchResults} from '../../services'; import {resetScreenType} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; -import { - CategoryPreviewType, - ProfilePreviewType, - ScreenType, - SearchCategoryType, -} from '../../types'; +import {CategoryPreviewType, ProfilePreviewType, ScreenType} from '../../types'; import { getRecentlySearchedCategories, getRecentlySearchedUsers, - normalize, - SCREEN_HEIGHT, - SCREEN_WIDTH, } from '../../utils'; /** @@ -38,11 +41,8 @@ import { const SearchScreen: React.FC = () => { const {recentSearches} = useSelector((state: RootState) => state.taggUsers); - const { - profile: {university = ''}, - } = useSelector((state: RootState) => state.user); const [query, setQuery] = useState<string>(''); - const [results, setResults] = useState<Array<any> | undefined>(undefined); + const [results, setResults] = useState<SectionListData<any>[] | undefined>(); const [recents, setRecents] = useState<Array<ProfilePreviewType>>( recentSearches ?? [], ); @@ -50,26 +50,12 @@ const SearchScreen: React.FC = () => { CategoryPreviewType[] >([]); const [searching, setSearching] = useState(false); - const top = Animated.useValue(-SCREEN_HEIGHT); - const defaultButtons: SearchCategoryType[] = [21, 22, 23, 24].map((year) => ({ - id: -1, - name: `${university.split(' ')[0]} '${year}`, - category: university, - })); - const [keyboardVisible, setKeyboardVisible] = React.useState( - 'keyboardVisible', - ); - useEffect(() => { - const showKeyboard = () => setKeyboardVisible('keyboardVisibleTrue'); - Keyboard.addListener('keyboardWillShow', showKeyboard); - return () => Keyboard.removeListener('keyboardWillShow', showKeyboard); - }, []); + /* + * Animated value + */ + const animationProgress = useSharedValue<number>(0); + const [searchBarHeight, setSearchBarHeight] = useState<number>(0); - useEffect(() => { - const hideKeyboard = () => setKeyboardVisible('keyboardVisibleFalse'); - Keyboard.addListener('keyboardWillHide', hideKeyboard); - return () => Keyboard.removeListener('keyboardWillHide', hideKeyboard); - }, []); const dispatch = useDispatch(); /* @@ -122,12 +108,22 @@ const SearchScreen: React.FC = () => { useEffect(() => { if (searching) { loadRecentlySearched().then(() => { - timing(top, topInConfig).start(); + animationProgress.value = withTiming(1, { + duration: 180, + easing: Easing.bezier(0.31, 0.14, 0.66, 0.82), + }); }); } else { setQuery(''); handleBlur(); - timing(top, topOutConfig).start(() => setResults(undefined)); + animationProgress.value = withTiming( + 0, + {duration: 180, easing: Easing.inOut(Easing.ease)}, + () => { + 'worklet'; + runOnJS(setResults)(undefined); + }, + ); } }, [searching]); @@ -153,16 +149,6 @@ const SearchScreen: React.FC = () => { } }; - const topInConfig = { - duration: 180, - toValue: 0, - easing: Easing.bezier(0.31, 0.14, 0.66, 0.82), - }; - const topOutConfig = { - duration: 180, - toValue: -SCREEN_HEIGHT, - easing: Easing.inOut(Easing.ease), - }; const handleFocus = () => { setSearching(true); }; @@ -172,9 +158,12 @@ const SearchScreen: React.FC = () => { const handleCancel = () => { setSearching(false); }; + const onSearchBarLayout = (e: LayoutChangeEvent) => { + setSearchBarHeight(e.nativeEvent.layout.height); + }; return ( - <SafeAreaView style={styles.screenContainer}> + <SafeAreaView style={styles.container}> <StatusBar barStyle="dark-content" /> <SearchBar onCancel={handleCancel} @@ -182,98 +171,39 @@ const SearchScreen: React.FC = () => { onBlur={handleBlur} onFocus={handleFocus} value={query} - {...{top, searching}} + onLayout={onSearchBarLayout} + {...{animationProgress, searching}} /> - <ScrollView - scrollEnabled={!searching} - keyboardShouldPersistTaps={'always'} - stickyHeaderIndices={[4]} - contentContainerStyle={styles.contentContainer} - showsVerticalScrollIndicator={false}> - <SearchCategories defaultButtons={defaultButtons} /> - <SearchResultsBackground {...{top}}> - {results === undefined && - recents.length + recentCategories.length !== 0 ? ( + <SearchCategories useSuggestions={false} /> + <SearchResultsBackground + {...{searching, searchBarHeight, animationProgress}}> + {results === undefined ? ( + recents.length + recentCategories.length > 0 && ( <RecentSearches sectionTitle="Recent" onPress={clearRecentlySearched} screenType={ScreenType.Search} {...{recents, recentCategories}} /> - ) : ( - <SearchResultList - {...{results}} - keyboardVisible={keyboardVisible === 'keyboardVisibleTrue'} - previewType={'Search'} - screenType={ScreenType.Search} - /> - )} - </SearchResultsBackground> - </ScrollView> + ) + ) : ( + <SearchResultList + {...{results}} + previewType={'Search'} + screenType={ScreenType.Search} + /> + )} + </SearchResultsBackground> <TabsGradient /> </SafeAreaView> ); }; const styles = StyleSheet.create({ - screenContainer: { + container: { + flex: 1, paddingTop: 15, backgroundColor: '#fff', }, - contentContainer: { - height: SCREEN_HEIGHT, - paddingTop: '2%', - paddingBottom: SCREEN_HEIGHT / 3, - paddingHorizontal: '3%', - }, - header: { - marginVertical: 20, - zIndex: 1, - }, - recentsHeaderContainer: { - flexDirection: 'row', - }, - recentsHeader: { - fontSize: 17, - fontWeight: 'bold', - flexGrow: 1, - }, - clear: { - fontSize: normalize(17), - fontWeight: 'bold', - color: TAGG_LIGHT_BLUE, - }, - image: { - width: SCREEN_WIDTH, - height: SCREEN_WIDTH, - }, - textContainer: { - marginTop: '10%', - }, - headerText: { - color: '#fff', - fontSize: normalize(32), - fontWeight: '600', - textAlign: 'center', - marginBottom: '4%', - marginHorizontal: '10%', - }, - subtext: { - color: '#fff', - fontSize: normalize(16), - fontWeight: '600', - textAlign: 'center', - marginHorizontal: '10%', - }, - cancelButton: { - position: 'absolute', - height: '100%', - justifyContent: 'center', - paddingHorizontal: 5, - }, - cancelText: { - color: '#818181', - fontWeight: '600', - }, }); export default SearchScreen; diff --git a/src/screens/suggestedPeople/SPBody.tsx b/src/screens/suggestedPeople/SPBody.tsx index 824f8b1c..fa69d812 100644 --- a/src/screens/suggestedPeople/SPBody.tsx +++ b/src/screens/suggestedPeople/SPBody.tsx @@ -3,26 +3,18 @@ import React, {Fragment, useEffect, useMemo, useState} from 'react'; import {StyleSheet, Text, View} from 'react-native'; import {Image} from 'react-native-animatable'; import {TouchableOpacity} from 'react-native-gesture-handler'; -import Animated from 'react-native-reanimated'; -import {useStore} from 'react-redux'; import RequestedButton from '../../assets/ionicons/requested-button.svg'; -import {TaggsBar} from '../../components'; +import {SPTaggsBar} from '../../components'; import {BadgesDropdown, MutualFriends} from '../../components/suggestedPeople'; import {BADGE_DATA} from '../../constants/badges'; -import {RootState} from '../../store/rootReducer'; import { ProfilePreviewType, ScreenType, SuggestedPeopleDataType, UniversityBadge, } from '../../types'; -import { - canViewProfile, - isIPhoneX, - normalize, - SCREEN_HEIGHT, - SCREEN_WIDTH, -} from '../../utils'; +import {isIPhoneX, normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import {useSharedValue} from 'react-native-reanimated'; interface SPBodyProps { item: SuggestedPeopleDataType; @@ -56,7 +48,6 @@ const SPBody: React.FC<SPBodyProps> = ({ }[] >([]); const navigation = useNavigation(); - const state: RootState = useStore().getState(); useEffect(() => { const newBadges: {badge: UniversityBadge; img: any}[] = []; const findBadgeIcons = (badge: UniversityBadge) => { @@ -159,12 +150,9 @@ const SPBody: React.FC<SPBodyProps> = ({ {user.id !== loggedInUserId && <FriendButton />} </View> </View> - <TaggsBar - y={Animated.useValue(0)} + <SPTaggsBar userXId={user.id === loggedInUserId ? undefined : user.id} - profileBodyHeight={0} screenType={screenType} - whiteRing={true} linkedSocials={social_links} /> <View style={styles.marginManager}> diff --git a/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx b/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx index a296351f..d6812f41 100644 --- a/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx +++ b/src/screens/suggestedPeople/SuggestedPeopleScreen.tsx @@ -226,7 +226,7 @@ const SuggestedPeopleScreen: React.FC = () => { /> ); }} - keyExtractor={(item, index) => index.toString()} + keyExtractor={(_, index) => index.toString()} showsVerticalScrollIndicator={false} onViewableItemsChanged={onViewableItemsChanged} onEndReached={() => setPage(page + 1)} |
