From b9bdcb8280bc006b90bc15539c0370305efbb283 Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Mon, 16 Oct 2023 12:34:15 +0200 Subject: [PATCH 1/9] feat(lib): resolve certain issues with the sample and fix unread message count --- lib/src/entities/chat.ts | 27 ++-- samples/react-native-group-chat/App.tsx | 138 +++++++++++------- .../bottom-sheet/BottomSheetTextInput.tsx | 66 +++++++++ .../components/bottom-sheet/index.ts | 1 + .../screens/ordinary/chat/Chat.tsx | 22 ++- .../ordinary/login-screen/LoginScreen.tsx | 49 ++++--- .../new-chat-screen/NewChatScreen.tsx | 8 + .../screens/tabs/home/HomeScreen.tsx | 51 +++++++ .../screens/tabs/home/Navigator.tsx | 112 +++++--------- .../screens/tabs/profile/ProfileScreen.tsx | 15 +- samples/react-native-group-chat/types.ts | 13 +- 11 files changed, 327 insertions(+), 175 deletions(-) create mode 100644 samples/react-native-group-chat/components/bottom-sheet/BottomSheetTextInput.tsx create mode 100644 samples/react-native-group-chat/components/bottom-sheet/index.ts diff --git a/lib/src/entities/chat.ts b/lib/src/entities/chat.ts index 7cd4931e..ac773fc3 100644 --- a/lib/src/entities/chat.ts +++ b/lib/src/entities/chat.ts @@ -960,21 +960,28 @@ export class Chat { const membershipsWithTimetokens = userMemberships.memberships.filter( (membership) => membership.lastReadMessageTimetoken ) + const membershipsWithoutTimetokens = userMemberships.memberships.filter( + (membership) => !membership.lastReadMessageTimetoken + ) const relevantTimetokens = membershipsWithTimetokens.map((m) => m.lastReadMessageTimetoken) - const relevantChannelIds = membershipsWithTimetokens.map((m) => m.channel.id) + const channelIdsWithTimetokens = membershipsWithTimetokens.map((m) => m.channel.id) + const channelIdsWithoutTimetokens = membershipsWithoutTimetokens.map((m) => m.channel.id) - if (!relevantChannelIds.length) { + if (!channelIdsWithTimetokens.length && !channelIdsWithoutTimetokens.length) { return [] } const response = await this.sdk.messageCounts({ - channels: relevantChannelIds, - channelTimetokens: relevantTimetokens as string[], + channels: [...channelIdsWithTimetokens, ...channelIdsWithoutTimetokens], + channelTimetokens: [ + ...relevantTimetokens, + ...channelIdsWithoutTimetokens.map(() => "0"), + ] as string[], }) return Object.keys(response.channels) .map((key) => { - const relevantMembership = membershipsWithTimetokens.find((m) => m.channel.id === key) + const relevantMembership = userMemberships.memberships.find((m) => m.channel.id === key) if (!relevantMembership) { throw `Cannot find channel with id ${key}` @@ -992,11 +999,7 @@ export class Chat { async markAllMessagesAsRead(params: Omit = {}) { const userMemberships = await this.currentUser.getMemberships(params) - const membershipsWithTimetokens = userMemberships.memberships.filter( - (membership) => membership.lastReadMessageTimetoken - ) - - const relevantChannelIds = membershipsWithTimetokens.map((m) => m.channel.id) + const relevantChannelIds = userMemberships.memberships.map((m) => m.channel.id) if (!relevantChannelIds.length) { return @@ -1012,12 +1015,12 @@ export class Chat { lastMessagesFromMembershipChannels.channels[encodeURIComponent(relevantChannelId)] const relevantLastMessageTimetoken = - relevantLastMessage && relevantLastMessage[0] ? relevantLastMessage[0].timetoken : "" + relevantLastMessage && relevantLastMessage[0] ? relevantLastMessage[0].timetoken : "0" return { id: relevantChannelId, custom: { - ...membershipsWithTimetokens[i].custom, + ...userMemberships.memberships[i].custom, lastReadMessageTimetoken: relevantLastMessageTimetoken, }, } diff --git a/samples/react-native-group-chat/App.tsx b/samples/react-native-group-chat/App.tsx index 8c0da957..bfc1bcf6 100644 --- a/samples/react-native-group-chat/App.tsx +++ b/samples/react-native-group-chat/App.tsx @@ -1,19 +1,18 @@ -import { useContext, useEffect, useState } from "react" +import React, { useContext, useEffect, useState } from "react" import { View, StyleSheet, ActivityIndicator, - KeyboardAvoidingView, - Platform, LogBox, + TouchableHighlight, + TouchableOpacity, } from "react-native" import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context" import { GestureHandlerRootView } from "react-native-gesture-handler" import { BottomSheetModalProvider } from "@gorhom/bottom-sheet" import { NavigationContainer } from "@react-navigation/native" -import { createBottomTabNavigator } from "@react-navigation/bottom-tabs" import { createStackNavigator, StackScreenProps } from "@react-navigation/stack" -import { MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons" +import { MaterialCommunityIcons } from "@expo/vector-icons" import { StatusBar } from "expo-status-bar" import { Channel, Chat, Membership, User } from "@pubnub/chat" import { @@ -24,20 +23,32 @@ import { } from "@expo-google-fonts/roboto" import "react-native-get-random-values" -import { MentionsScreen, HomeStackScreen, ProfileScreen } from "./screens/tabs" -import { LoginScreen } from "./screens/ordinary" +import { HomeStackScreen } from "./screens/tabs" +import { + ChatScreen, + ChatSettings, + LoginScreen, + NewChatScreen, + NewGroupScreen, + PinnedMessage, + ThreadReply, +} from "./screens/ordinary" import { ChatContext } from "./context" -import { RootStackParamList, BottomTabsParamList } from "./types" -import { defaultTheme, colorPalette as colors } from "./ui-components" +import { RootStackParamList } from "./types" +import { defaultTheme, colorPalette as colors, Text } from "./ui-components" +import { Avatar } from "./components" LogBox.ignoreLogs(["Require cycle:", "Sending"]) -const Tab = createBottomTabNavigator() const MainStack = createStackNavigator() -function TabNavigator({ route }: StackScreenProps) { +function MainRoutesNavigator({ route }: StackScreenProps) { const { name } = route.params - const { setChat, chat } = useContext(ChatContext) + const { setChat, chat, currentChannel, currentChannelMembers } = useContext(ChatContext) + + const interlocutor = + currentChannel?.type === "direct" && + currentChannelMembers.map((m) => m.user).filter((u) => u.id !== chat?.currentUser.id)[0] useEffect(() => { async function init() { @@ -65,7 +76,7 @@ function TabNavigator({ route }: StackScreenProps) { } return ( - ) { }, headerStatusBarHeight: 0, // there's some extra padding on top of the header without this headerTintColor: colors.neutral0, - tabBarStyle: { backgroundColor: colors.navy50 }, - tabBarActiveTintColor: colors.neutral900, - tabBarInactiveTintColor: colors.navy500, - tabBarHideOnKeyboard: true, }} > - ( - - ), + headerTitle: "Home", }} /> - ( - - ), - }} + ({ + headerTitle: () => + currentChannel && ( + navigation.navigate("ChatSettings")} + style={{ paddingVertical: 8, paddingHorizontal: 30, borderRadius: 6 }} + > + + + + {interlocutor ? interlocutor.name : currentChannel?.name} + + + + ), + headerRight: () => { + return ( + + navigation.navigate("PinnedMessage", { channelId: currentChannel?.id }) + } + style={{ paddingRight: 24 }} + > + + + ) + }, + })} /> - ( - - ), - }} + + + + - + + ) } @@ -191,18 +229,12 @@ function App() { style={[styles.safeArea, { backgroundColor: defaultTheme.colors.navy800 }]} edges={["top", "left", "right"]} > - {/* TODO: for some reason KeyboardAvoidingView doesn't work on any page other than login */} - - - - - - - - + + + + + + diff --git a/samples/react-native-group-chat/components/bottom-sheet/BottomSheetTextInput.tsx b/samples/react-native-group-chat/components/bottom-sheet/BottomSheetTextInput.tsx new file mode 100644 index 00000000..a16db906 --- /dev/null +++ b/samples/react-native-group-chat/components/bottom-sheet/BottomSheetTextInput.tsx @@ -0,0 +1,66 @@ +import React from "react" +import { BottomSheetTextInput as GorhomBottomSheetTextInput } from "@gorhom/bottom-sheet" +import { MaterialIcons } from "@expo/vector-icons" +import { StyleSheet, View, ViewStyle } from "react-native" +import { TextInputProps as RNTextInputProps } from "react-native/Libraries/Components/TextInput/TextInput" +import { colorPalette as colors, Gap, Text } from "../../ui-components" + +type BottomSheetTextInputProps = { + label?: string + icon?: keyof typeof MaterialIcons.glyphMap + variant?: "base" | "search" + containerStyle?: ViewStyle +} + +export const BottomSheetTextInput = ({ + variant = "base", + label, + icon, + containerStyle, + style, + ...rest +}: BottomSheetTextInputProps & RNTextInputProps) => { + const styles = createStyles({ variant }) + return ( + + {label ? ( + <> + {label} + + + ) : null} + + + + + + ) +} + +const createStyles = ({ variant }: Required>) => + StyleSheet.create({ + wrapper: { + alignItems: "center", + borderRadius: 6, + borderWidth: 1, + flexDirection: "row", + justifyContent: "center", + paddingHorizontal: 12, + borderColor: variant === "base" ? colors.navy300 : colors.neutral50, + height: variant === "base" ? 48 : 42, + backgroundColor: variant === "base" ? undefined : colors.neutral50, + }, + icon: { + marginRight: 8, + }, + input: { + alignSelf: "stretch", + flex: 1, + fontFamily: "Roboto_400Regular", + fontSize: 16, + }, + }) diff --git a/samples/react-native-group-chat/components/bottom-sheet/index.ts b/samples/react-native-group-chat/components/bottom-sheet/index.ts new file mode 100644 index 00000000..47f10efc --- /dev/null +++ b/samples/react-native-group-chat/components/bottom-sheet/index.ts @@ -0,0 +1 @@ +export * from "./BottomSheetTextInput" diff --git a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx index 0533627d..b37037a4 100644 --- a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx +++ b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx @@ -1,5 +1,12 @@ import React, { useState, useCallback, useEffect, useContext, useRef } from "react" -import { StyleSheet, View, ActivityIndicator, TouchableOpacity, FlatList } from "react-native" +import { + StyleSheet, + View, + ActivityIndicator, + TouchableOpacity, + FlatList, + SafeAreaView, +} from "react-native" import { GiftedChat, Bubble } from "react-native-gifted-chat" import { StackScreenProps } from "@react-navigation/stack" import { User, MessageDraft, Message, Channel } from "@pubnub/chat" @@ -232,12 +239,13 @@ export function ChatScreen({}: StackScreenProps) { } const handleInputChange = useCallback( - (text: string) => { - if (!messageDraft || text === "") { + (giftedChatText: string) => { + if (!messageDraft || giftedChatText === "") { + setText("") return } - messageDraft.onChange(text).then((suggestionObject) => { + messageDraft.onChange(giftedChatText).then((suggestionObject) => { setSuggestedData( suggestionObject.users.suggestedUsers.length ? suggestionObject.users.suggestedUsers @@ -253,7 +261,7 @@ export function ChatScreen({}: StackScreenProps) { setText(messageDraft.value) setShowSuggestedData(true) }, - [messageDraft, currentChannel] + [messageDraft] ) const renderBubble = (props: Bubble["props"]) => { @@ -294,7 +302,7 @@ export function ChatScreen({}: StackScreenProps) { } return ( - + onSend(messages)} @@ -321,7 +329,7 @@ export function ChatScreen({}: StackScreenProps) { messageContainerRef={giftedChatRef} /> - + ) } diff --git a/samples/react-native-group-chat/screens/ordinary/login-screen/LoginScreen.tsx b/samples/react-native-group-chat/screens/ordinary/login-screen/LoginScreen.tsx index 86147ca3..74a17e2b 100644 --- a/samples/react-native-group-chat/screens/ordinary/login-screen/LoginScreen.tsx +++ b/samples/react-native-group-chat/screens/ordinary/login-screen/LoginScreen.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react" -import { View, StyleSheet } from "react-native" +import { View, StyleSheet, Platform, KeyboardAvoidingView } from "react-native" import { StackScreenProps } from "@react-navigation/stack" import { Text, Button, Gap, TextInput, colorPalette as colors } from "../../../ui-components" @@ -10,27 +10,32 @@ export function LoginScreen({ navigation }: StackScreenProps - - - - - Log in to Sample Chat App - - - - - Built with PubNub Chat SDK for JavaScript and TypeScript. - - - - - - - - + + + + + + + Log in to Sample Chat App + + + + + Built with PubNub Chat SDK for JavaScript and TypeScript. + + + + + + + + + ) } diff --git a/samples/react-native-group-chat/screens/ordinary/new-chat-screen/NewChatScreen.tsx b/samples/react-native-group-chat/screens/ordinary/new-chat-screen/NewChatScreen.tsx index 7867e9ee..d6c8e1b3 100644 --- a/samples/react-native-group-chat/screens/ordinary/new-chat-screen/NewChatScreen.tsx +++ b/samples/react-native-group-chat/screens/ordinary/new-chat-screen/NewChatScreen.tsx @@ -21,6 +21,14 @@ export function NewChatScreen({ navigation }: StackScreenProps([]) const channels = memberships.map((m) => m.channel) + const currentUserDirectChannels = channels.filter((c) => c.type === "direct") const currentUserGroupChannels = channels.filter((c) => c.type === "group") const currentUserPublicChannels = channels.filter((c) => c.type === "public") @@ -34,6 +35,36 @@ export function HomeScreen({ navigation }: StackScreenProps { + if (!chat) { + return + } + + chat.listenForEvents({ + channel: chat.currentUser.id, + type: "custom", + method: "publish", + callback: async (evt) => { + if (evt.payload.action === "DIRECT_CONVERSATION_STARTED") { + const { memberships } = await chat.currentUser.getMemberships() + setMemberships(memberships) + } + }, + }) + }, [chat]) + + useEffect(() => { + const disconnectFuncs = channels.map((ch) => + ch.connect((message) => { + fetchUnreadMessagesCount() + }) + ) + + return () => { + disconnectFuncs.forEach((func) => func()) + } + }, [channels, memberships]) + useEffect(() => { async function init() { if (!chat) return @@ -50,6 +81,26 @@ export function HomeScreen({ navigation }: StackScreenProps { + async function handleScreenFocus() { + if (!chat) { + return + } + + const [{ memberships }, { users }] = await Promise.all([ + chat.currentUser.getMemberships(), + chat.getUsers({}), + ]) + + setUsers(users) + setMemberships(memberships) + } + + handleScreenFocus() + }, [chat, setMemberships, setUsers]) + ) + useFocusEffect( React.useCallback(() => { fetchUnreadMessagesCount() diff --git a/samples/react-native-group-chat/screens/tabs/home/Navigator.tsx b/samples/react-native-group-chat/screens/tabs/home/Navigator.tsx index 2cb56416..42f4139d 100644 --- a/samples/react-native-group-chat/screens/tabs/home/Navigator.tsx +++ b/samples/react-native-group-chat/screens/tabs/home/Navigator.tsx @@ -1,32 +1,24 @@ import React, { useContext } from "react" -import { createStackNavigator, StackScreenProps } from "@react-navigation/stack" -import { View, TouchableHighlight, TouchableOpacity } from "react-native" -import { MaterialCommunityIcons } from "@expo/vector-icons" +import { StackScreenProps } from "@react-navigation/stack" +import { View } from "react-native" +import { MaterialCommunityIcons, MaterialIcons } from "@expo/vector-icons" -import { BottomTabsParamList, HomeStackParamList } from "../../../types" +import { BottomTabsParamList, RootStackParamList } from "../../../types" import { Text, colorPalette as colors } from "../../../ui-components" import { ChatContext } from "../../../context" import { Avatar } from "../../../components" import { HomeScreen } from "./HomeScreen" -import { - ChatScreen, - NewChatScreen, - NewGroupScreen, - ThreadReply, - ChatSettings, - PinnedMessage, -} from "../../ordinary" +import { createBottomTabNavigator } from "@react-navigation/bottom-tabs" +import { MentionsScreen } from "../mentions" +import { ProfileScreen } from "../profile" -const HomeStack = createStackNavigator() +const Tab = createBottomTabNavigator() -export function HomeStackScreen({ route }: StackScreenProps) { - const { chat, currentChannel, currentChannelMembers } = useContext(ChatContext) - const interlocutor = - currentChannel?.type === "direct" && - currentChannelMembers.map((m) => m.user).filter((u) => u.id !== chat?.currentUser.id)[0] +export function HomeStackScreen({ route }: StackScreenProps) { + const { chat } = useContext(ChatContext) return ( - - ), + tabBarLabel: "Home", + tabBarIcon: ({ color }) => ( + + ), })} /> - ({ - headerTitle: () => - currentChannel && ( - navigation.navigate("ChatSettings")} - style={{ paddingVertical: 8, paddingHorizontal: 30, borderRadius: 6 }} - > - - - - {interlocutor ? interlocutor.name : currentChannel?.name} - - - - ), - headerRight: () => { - return ( - - navigation.navigate("PinnedMessage", { channelId: currentChannel?.id }) - } - style={{ paddingRight: 24 }} - > - - - ) - }, - })} - /> - - - - ( + + ), + }} /> - ( + + ), + }} /> - + ) } diff --git a/samples/react-native-group-chat/screens/tabs/profile/ProfileScreen.tsx b/samples/react-native-group-chat/screens/tabs/profile/ProfileScreen.tsx index dba29d07..ed51af09 100644 --- a/samples/react-native-group-chat/screens/tabs/profile/ProfileScreen.tsx +++ b/samples/react-native-group-chat/screens/tabs/profile/ProfileScreen.tsx @@ -5,8 +5,9 @@ import { BottomSheetModal, BottomSheetBackdrop } from "@gorhom/bottom-sheet" import { BottomTabsParamList } from "../../../types" import { ChatContext } from "../../../context" -import { Button, Text, Gap, TextInput, colorPalette as colors } from "../../../ui-components" +import { Button, Text, Gap, colorPalette as colors } from "../../../ui-components" import { Avatar } from "../../../components" +import { BottomSheetTextInput } from "../../../components/bottom-sheet" export function ProfileScreen({ navigation, @@ -76,7 +77,7 @@ export function ProfileScreen({ Change your name - + @@ -107,4 +108,14 @@ const styles = StyleSheet.create({ borderRadius: 6, width: 120, }, + textInput: { + alignSelf: "stretch", + marginHorizontal: 12, + marginBottom: 12, + padding: 12, + borderRadius: 12, + backgroundColor: "white", + color: "black", + textAlign: "center", + }, }) diff --git a/samples/react-native-group-chat/types.ts b/samples/react-native-group-chat/types.ts index 56507cc8..6754e987 100644 --- a/samples/react-native-group-chat/types.ts +++ b/samples/react-native-group-chat/types.ts @@ -5,23 +5,24 @@ import { EnhancedIMessage } from "./utils" export type RootStackParamList = { login: undefined - tabs: { name: string } -} - -export type HomeStackParamList = { - Home: { name: string } + mainRoutes: { name: string } Chat: undefined NewChat: undefined NewGroup: undefined ThreadReply: { parentMessage: EnhancedIMessage } ChatSettings: undefined PinnedMessage: undefined + HomeStack: NavigatorScreenParams & { name: string } +} + +export type HomeStackParamList = { + Home: { name: string } } export type HomeStackNavigation = NavigationProp export type BottomTabsParamList = { - HomeStack: NavigatorScreenParams & { name: string } + Home: { name: string } Mentions: undefined Profile: undefined } From d83e2513109ee093d45c15a898978b0c32fe3459 Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Mon, 16 Oct 2023 12:50:52 +0200 Subject: [PATCH 2/9] feat(lib): add a better loader for chat --- .../react-native-group-chat/screens/ordinary/chat/Chat.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx index b37037a4..b66ecd94 100644 --- a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx +++ b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx @@ -25,7 +25,7 @@ export function ChatScreen({}: StackScreenProps) { useContext(ChatContext) const navigation = useNavigation() const [isMoreMessages, setIsMoreMessages] = useState(true) - const [isLoadingMoreMessages, setIsLoadingMoreMessages] = useState(false) + const [isLoadingMoreMessages, setIsLoadingMoreMessages] = useState(true) const [giftedChatMappedMessages, setGiftedChatMappedMessages] = useState([]) const [typingData, setTypingData] = useState([]) const [messageDraft, setMessageDraft] = useState(null) @@ -155,6 +155,7 @@ export function ChatScreen({}: StackScreenProps) { if (!currentChannel) { return } + setIsLoadingMoreMessages(true) setGiftedChatMappedMessages([]) const historicalMessagesObject = await currentChannel.getHistory({ count: 5 }) @@ -194,6 +195,8 @@ export function ChatScreen({}: StackScreenProps) { .reverse() ) ) + + setIsLoadingMoreMessages(false) } switchChannelImplementation() From ef265a7489a66afce8c97db30ae7ad465cbe3c5e Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Mon, 16 Oct 2023 16:02:33 +0200 Subject: [PATCH 3/9] feat(lib): fix interlocutors --- samples/react-native-group-chat/App.tsx | 108 ++++++++++++------ .../screens/ordinary/chat/Chat.tsx | 17 ++- .../screens/tabs/home/HomeScreen.tsx | 50 +++----- 3 files changed, 91 insertions(+), 84 deletions(-) diff --git a/samples/react-native-group-chat/App.tsx b/samples/react-native-group-chat/App.tsx index bfc1bcf6..212f61fb 100644 --- a/samples/react-native-group-chat/App.tsx +++ b/samples/react-native-group-chat/App.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from "react" +import React, { useCallback, useContext, useEffect, useMemo, useState } from "react" import { View, StyleSheet, @@ -156,12 +156,13 @@ function MainRoutesNavigator({ route }: StackScreenProps(null) const [users, setUsers] = useState([]) + const [interlocutors, setInterlocutors] = useState<{ [channelId: string]: User }>({}) const [loading, setLoading] = useState(false) const [currentChannel, setCurrentChannel] = useState() const [currentChannelMembers, setCurrentChannelMembers] = useState([]) const [userMemberships, setUserMemberships] = useState([]) - async function setCurrentChannelWithMembers(channel: Channel | null) { + const setCurrentChannelWithMembers = useCallback(async (channel: Channel | null) => { if (!channel) { setCurrentChannelMembers([]) setCurrentChannel(null) @@ -171,27 +172,48 @@ function App() { const { members } = await channel.getMembers() setCurrentChannelMembers(members) setCurrentChannel(channel) - } + }, []) + + const getUser = useCallback( + (userId: string) => { + const existingUser = users.find((u) => u.id === userId) + if (!existingUser) { + chat?.getUser(userId).then((fetchedUser) => { + if (fetchedUser) setUsers((users) => [...users, fetchedUser]) + }) + return null + } + return existingUser + }, + [chat, users] + ) + + const getInterlocutor = useCallback( + (channel: Channel) => { + if (!chat) return null + + if (interlocutors[channel.id]) { + return getUser(interlocutors[channel.id].id) + } - function getUser(userId: string) { - const existingUser = users.find((u) => u.id === userId) - if (!existingUser) { - chat?.getUser(userId).then((fetchedUser) => { - if (fetchedUser) setUsers((users) => [...users, fetchedUser]) + channel.getMembers().then(({ members }) => { + const filteredMembers = members.filter((m) => m.user.id !== chat.currentUser.id) + const user = filteredMembers.length ? filteredMembers[0].user : null + + if (!user) { + return + } + + setInterlocutors((currentInterlocutors) => ({ + ...currentInterlocutors, + [channel.id]: user, + })) }) - return null - } - return existingUser - } - function getInterlocutor(channel: Channel) { - if (!chat) return null - const userId = channel.id - .replace("direct.", "") - .replace(chat?.currentUser.id, "") - .replace("&", "") - return getUser(userId) - } + return null + }, + [chat, getUser, interlocutors] + ) const [fontsLoaded] = useFonts({ Roboto_400Regular, @@ -199,28 +221,40 @@ function App() { Roboto_700Bold, }) + const contextValue = useMemo( + () => ({ + loading, + setLoading, + chat, + setChat, + currentChannel, + setCurrentChannel: setCurrentChannelWithMembers, + currentChannelMembers, + users, + setUsers, + getUser, + getInterlocutor, + memberships: userMemberships, + setMemberships: setUserMemberships, + }), + [ + chat, + currentChannel, + currentChannelMembers, + getInterlocutor, + getUser, + loading, + userMemberships, + users, + ] + ) + if (!fontsLoaded) { return null } return ( - + diff --git a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx index b66ecd94..49c83cfa 100644 --- a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx +++ b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useEffect, useContext, useRef } from "react" +import React, { useState, useCallback, useEffect, useContext, useRef, useMemo } from "react" import { StyleSheet, View, @@ -25,7 +25,7 @@ export function ChatScreen({}: StackScreenProps) { useContext(ChatContext) const navigation = useNavigation() const [isMoreMessages, setIsMoreMessages] = useState(true) - const [isLoadingMoreMessages, setIsLoadingMoreMessages] = useState(true) + const [isLoadingMoreMessages, setIsLoadingMoreMessages] = useState(false) const [giftedChatMappedMessages, setGiftedChatMappedMessages] = useState([]) const [typingData, setTypingData] = useState([]) const [messageDraft, setMessageDraft] = useState(null) @@ -34,8 +34,9 @@ export function ChatScreen({}: StackScreenProps) { const giftedChatRef = useRef>(null) const [lastAffectedNameOccurrenceIndex, setLastAffectedNameOccurrenceIndex] = useState(-1) const [text, setText] = useState("") - const currentChannelMembership = currentChannelMembers.find( - (m) => m.user.id === chat?.currentUser.id + const currentChannelMembership = useMemo( + () => currentChannelMembers.find((m) => m.user.id === chat?.currentUser.id), + [chat?.currentUser.id, currentChannelMembers] ) const { renderFooter, renderMessageText, renderChatFooter } = useCommonChatRenderers({ typingData, @@ -78,7 +79,6 @@ export function ChatScreen({}: StackScreenProps) { const handleEmoji = useCallback( (message: Message) => { - console.log("message", message) const copiedMessages = [...giftedChatMappedMessages] const index = copiedMessages.findIndex( @@ -155,7 +155,6 @@ export function ChatScreen({}: StackScreenProps) { if (!currentChannel) { return } - setIsLoadingMoreMessages(true) setGiftedChatMappedMessages([]) const historicalMessagesObject = await currentChannel.getHistory({ count: 5 }) @@ -195,12 +194,10 @@ export function ChatScreen({}: StackScreenProps) { .reverse() ) ) - - setIsLoadingMoreMessages(false) } switchChannelImplementation() - }, [currentChannel, currentChannelMembership, getUser]) + }, [currentChannel, currentChannelMembership]) useEffect(() => { if (!currentChannel) { @@ -221,7 +218,7 @@ export function ChatScreen({}: StackScreenProps) { return () => { disconnect() } - }, [currentChannel, currentChannelMembership, getUser]) + }, [currentChannel, currentChannelMembership]) const resetInput = () => { if (!messageDraft) { diff --git a/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx b/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx index ca55a1c8..f35e0923 100644 --- a/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx +++ b/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useContext, useEffect, useState } from "react" +import React, { useCallback, useContext, useEffect, useMemo, useState } from "react" import { StyleSheet, ScrollView, TouchableHighlight, TouchableOpacity } from "react-native" import { useFocusEffect } from "@react-navigation/native" import { StackScreenProps } from "@react-navigation/stack" @@ -18,7 +18,7 @@ export function HomeScreen({ navigation }: StackScreenProps([]) - const channels = memberships.map((m) => m.channel) + const channels = useMemo(() => memberships.map((m) => m.channel), [memberships]) const currentUserDirectChannels = channels.filter((c) => c.type === "direct") const currentUserGroupChannels = channels.filter((c) => c.type === "group") @@ -65,47 +65,26 @@ export function HomeScreen({ navigation }: StackScreenProps { - async function init() { - if (!chat) return - const [, { memberships }, { users }] = await Promise.all([ - fetchUnreadMessagesCount(), - chat.currentUser.getMemberships(), - chat.getUsers({}), - ]) - - setUsers(users) - setMemberships(memberships) - } - - init() - }, [chat, fetchUnreadMessagesCount, setMemberships, setUsers]) - useFocusEffect( React.useCallback(() => { async function handleScreenFocus() { if (!chat) { return } + setCurrentChannel(null) - const [{ memberships }, { users }] = await Promise.all([ + const [, { memberships: refreshedMemberships }, { users }] = await Promise.all([ + fetchUnreadMessagesCount(), chat.currentUser.getMemberships(), chat.getUsers({}), ]) setUsers(users) - setMemberships(memberships) + setMemberships(refreshedMemberships) } handleScreenFocus() - }, [chat, setMemberships, setUsers]) - ) - - useFocusEffect( - React.useCallback(() => { - fetchUnreadMessagesCount() - setCurrentChannel(null) - }, []) + }, [chat, fetchUnreadMessagesCount, setCurrentChannel, setMemberships, setUsers]) ) const getFilteredChannels = useCallback( @@ -117,14 +96,11 @@ export function HomeScreen({ navigation }: StackScreenProps { - return unreadChannelCounts.filter( - (c) => c.channel.name && c.channel.name.toLowerCase().includes(searchText.toLowerCase()) - ) - }, - [searchText] - ) + const getFilteredUnreadChannels = useCallback(() => { + return unreadChannels.filter( + (c) => c.channel.name && c.channel.name.toLowerCase().includes(searchText.toLowerCase()) + ) + }, [searchText, unreadChannels]) const markAllMessagesAsRead = useCallback(async () => { if (!chat) return @@ -155,7 +131,7 @@ export function HomeScreen({ navigation }: StackScreenProps } > - {getFilteredUnreadChannels(unreadChannels).map(({ channel, count }) => { + {getFilteredUnreadChannels().map(({ channel, count }) => { const interlocutor = channel.type === "direct" && getInterlocutor(channel) const source = interlocutor || channel From dd906f02131b6edfa57e1cce555ba7f6de44cc91 Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Tue, 17 Oct 2023 14:15:08 +0200 Subject: [PATCH 4/9] feat(lib): add custom listeners realted to group chats --- lib/src/entities/channel.ts | 19 +++++++++---- lib/src/entities/chat.ts | 21 ++++----------- lib/src/entities/membership.ts | 6 ++--- samples/react-native-group-chat/.env.example | 4 +-- .../screens/ordinary/chat/Chat.tsx | 27 ++++++++++++++----- .../new-group-screen/NewGroupScreen.tsx | 12 +++++++++ .../screens/tabs/home/HomeScreen.tsx | 19 ++++++++++++- 7 files changed, 74 insertions(+), 34 deletions(-) diff --git a/lib/src/entities/channel.ts b/lib/src/entities/channel.ts index d62c610c..5274e1fa 100644 --- a/lib/src/entities/channel.ts +++ b/lib/src/entities/channel.ts @@ -420,11 +420,11 @@ export class Channel { this.disconnect = this.connect(callback) return { - membership: Membership.fromMembershipDTO( + membership: await Membership.fromMembershipDTO( this.chat, membershipsResponse.data[0], this.chat.currentUser as User - ), + ).setLastReadMessageTimetoken(String((await this.chat.sdk.time()).timetoken)), disconnect: this.disconnect, } } catch (error) { @@ -490,7 +490,11 @@ export class Channel { filter: `channel.id == '${this.id}'`, }) - return Membership.fromMembershipDTO(this.chat, response.data[0], user) + return await Membership.fromMembershipDTO( + this.chat, + response.data[0], + user + ).setLastReadMessageTimetoken(String((await this.chat.sdk.time()).timetoken)) } catch (error) { throw error } @@ -513,9 +517,14 @@ export class Channel { }, filter, }) + const freshtimetoken = await this.chat.sdk.time() - return response.data.map((dataPoint) => - Membership.fromChannelMemberDTO(this.chat, dataPoint, this) + return await Promise.all( + response.data.map(async (dataPoint) => + Membership.fromChannelMemberDTO(this.chat, dataPoint, this).setLastReadMessageTimetoken( + String(freshtimetoken.timetoken) + ) + ) ) } catch (error) { throw error diff --git a/lib/src/entities/chat.ts b/lib/src/entities/chat.ts index ac773fc3..38fb64ad 100644 --- a/lib/src/entities/chat.ts +++ b/lib/src/entities/chat.ts @@ -957,26 +957,15 @@ export class Chat { async getUnreadMessagesCounts(params: Omit = {}) { const userMemberships = await this.currentUser.getMemberships(params) - const membershipsWithTimetokens = userMemberships.memberships.filter( - (membership) => membership.lastReadMessageTimetoken - ) - const membershipsWithoutTimetokens = userMemberships.memberships.filter( - (membership) => !membership.lastReadMessageTimetoken - ) - const relevantTimetokens = membershipsWithTimetokens.map((m) => m.lastReadMessageTimetoken) - const channelIdsWithTimetokens = membershipsWithTimetokens.map((m) => m.channel.id) - const channelIdsWithoutTimetokens = membershipsWithoutTimetokens.map((m) => m.channel.id) - - if (!channelIdsWithTimetokens.length && !channelIdsWithoutTimetokens.length) { + if (!userMemberships.memberships.length) { return [] } const response = await this.sdk.messageCounts({ - channels: [...channelIdsWithTimetokens, ...channelIdsWithoutTimetokens], - channelTimetokens: [ - ...relevantTimetokens, - ...channelIdsWithoutTimetokens.map(() => "0"), - ] as string[], + channels: userMemberships.memberships.map((m) => m.channel.id), + channelTimetokens: userMemberships.memberships.map( + (m) => m.lastReadMessageTimetoken || "0" + ) as string[], }) return Object.keys(response.channels) diff --git a/lib/src/entities/membership.ts b/lib/src/entities/membership.ts index 61f54cbb..6eff661b 100644 --- a/lib/src/entities/membership.ts +++ b/lib/src/entities/membership.ts @@ -134,17 +134,17 @@ export class Membership { return this.custom?.lastReadMessageTimetoken } - async setLastReadMessage(message: Message) { + async setLastReadMessageTimetoken(timetoken: string) { try { const response = await this.update({ - custom: { ...this.custom, lastReadMessageTimetoken: message.timetoken }, + custom: { ...this.custom, lastReadMessageTimetoken: timetoken }, }) await this.chat.emitEvent({ channel: this.channel.id, type: "receipt", method: "signal", - payload: { messageTimetoken: message.timetoken }, + payload: { messageTimetoken: timetoken }, }) return response diff --git a/samples/react-native-group-chat/.env.example b/samples/react-native-group-chat/.env.example index 8e1f18c9..da835efe 100644 --- a/samples/react-native-group-chat/.env.example +++ b/samples/react-native-group-chat/.env.example @@ -1,2 +1,2 @@ -EXPO_PUBNUB_SUB_KEY= -EXPO_PUBNUB_PUB_KEY= \ No newline at end of file +EXPO_PUBLIC_PUBNUB_SUB_KEY= +EXPO_PUBLIC_PUBNUB_PUB_KEY= diff --git a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx index 49c83cfa..ccaf211d 100644 --- a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx +++ b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx @@ -69,10 +69,11 @@ export function ChatScreen({}: StackScreenProps) { } await message.pin() - const refreshedChannel = await chat.getChannel(currentChannel.id) - if (refreshedChannel) { - setCurrentChannel(refreshedChannel) - } + await currentChannel.update({ name: "Grupa chatowa 23" + Math.random() }) + // const refreshedChannel = await chat.getChannel(currentChannel.id) + // if (refreshedChannel) { + // setCurrentChannel(refreshedChannel) + // } }, [chat, currentChannel, setCurrentChannel] ) @@ -102,6 +103,18 @@ export function ChatScreen({}: StackScreenProps) { onToggleEmoji: handleEmoji, }) + useEffect(() => { + if (!currentChannel) { + return + } + console.log("hello", currentChannel) + const unstream = currentChannel.streamUpdates((ch) => { + console.log("ch", ch) + }) + + return unstream + }, [currentChannel]) + useEffect(() => { if (!giftedChatMappedMessages.length) { return @@ -160,8 +173,8 @@ export function ChatScreen({}: StackScreenProps) { const historicalMessagesObject = await currentChannel.getHistory({ count: 5 }) if (currentChannelMembership && historicalMessagesObject.messages.length) { - await currentChannelMembership.setLastReadMessage( - historicalMessagesObject.messages[historicalMessagesObject.messages.length - 1] + await currentChannelMembership.setLastReadMessageTimetoken( + historicalMessagesObject.messages[historicalMessagesObject.messages.length - 1].timetoken ) } @@ -206,7 +219,7 @@ export function ChatScreen({}: StackScreenProps) { const disconnect = currentChannel.connect((message) => { if (currentChannelMembership) { - currentChannelMembership.setLastReadMessage(message) + currentChannelMembership.setLastReadMessageTimetoken(message.timetoken) } setGiftedChatMappedMessages((currentMessages) => GiftedChat.append(currentMessages, [ diff --git a/samples/react-native-group-chat/screens/ordinary/new-group-screen/NewGroupScreen.tsx b/samples/react-native-group-chat/screens/ordinary/new-group-screen/NewGroupScreen.tsx index 5cb0a82f..168d3eb5 100644 --- a/samples/react-native-group-chat/screens/ordinary/new-group-screen/NewGroupScreen.tsx +++ b/samples/react-native-group-chat/screens/ordinary/new-group-screen/NewGroupScreen.tsx @@ -33,6 +33,18 @@ export function NewGroupScreen({ navigation }: StackScreenProps { + await chat.emitEvent({ + channel: u.id, + method: "publish", + payload: { + action: "GROUP_CONVERSATION_STARTED", + channelId: channel.id, + }, + }) + }) + ) setCurrentChannel(channel) setLoading(false) } diff --git a/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx b/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx index f35e0923..10c76c46 100644 --- a/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx +++ b/samples/react-native-group-chat/screens/tabs/home/HomeScreen.tsx @@ -40,7 +40,7 @@ export function HomeScreen({ navigation }: StackScreenProps { + if (evt.payload.action === "GROUP_CONVERSATION_STARTED") { + const { memberships } = await chat.currentUser.getMemberships() + setMemberships(memberships) + } + }, + }) + + return () => { + removeDirectChatListener() + removeGroupChatListener() + } }, [chat]) useEffect(() => { From 026fe940c7af38dfa492192e2668705b3384bdda Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Tue, 17 Oct 2023 14:28:17 +0200 Subject: [PATCH 5/9] feat(lib): add test changes --- lib/tests/channel.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tests/channel.test.ts b/lib/tests/channel.test.ts index 0be79770..e809bc97 100644 --- a/lib/tests/channel.test.ts +++ b/lib/tests/channel.test.ts @@ -285,7 +285,7 @@ describe("Channel test", () => { expect(unreadCount).toBe(false) const { messages } = await channel.getHistory() - membership = await membership.setLastReadMessage(messages[0]) + membership = await membership.setLastReadMessageTimetoken(messages[0].timetoken) unreadCount = await membership.getUnreadMessagesCount() expect(unreadCount).toBe(1) @@ -651,7 +651,7 @@ describe("Channel test", () => { const { timetoken } = await channel.sendText("New message") await sleep(150) // history calls have around 130ms of cache time const message = await channel.getMessage(timetoken) - await membership.setLastReadMessage(message) + await membership.setLastReadMessageTimetoken(message.timetoken) await sleep(150) // history calls have around 130ms of cache time expect(mockCallback).toHaveBeenCalledTimes(2) From 66de710917510f0f6caacbf928cd123b38506c9c Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Tue, 17 Oct 2023 15:03:22 +0200 Subject: [PATCH 6/9] feat(lib): add updates to pinning messages --- lib/src/entities/user.ts | 1 + samples/react-native-group-chat/App.tsx | 4 +--- .../screens/ordinary/chat/Chat.tsx | 17 ----------------- .../ordinary/pinned-message/PinnedMessage.tsx | 13 ++++++++++++- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/lib/src/entities/user.ts b/lib/src/entities/user.ts index cc864098..cd8b8e87 100644 --- a/lib/src/entities/user.ts +++ b/lib/src/entities/user.ts @@ -54,6 +54,7 @@ export class User { } get active() { + console.log("userid", this.id, new Date().getTime(), this.lastActiveTimestamp) return !!( this.lastActiveTimestamp && new Date().getTime() - this.lastActiveTimestamp <= this.chat.config.storeUserActivityInterval diff --git a/samples/react-native-group-chat/App.tsx b/samples/react-native-group-chat/App.tsx index 212f61fb..7d604fa2 100644 --- a/samples/react-native-group-chat/App.tsx +++ b/samples/react-native-group-chat/App.tsx @@ -121,9 +121,7 @@ function MainRoutesNavigator({ route }: StackScreenProps { return ( - navigation.navigate("PinnedMessage", { channelId: currentChannel?.id }) - } + onPress={() => navigation.navigate("PinnedMessage")} style={{ paddingRight: 24 }} > diff --git a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx index ccaf211d..a17423f3 100644 --- a/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx +++ b/samples/react-native-group-chat/screens/ordinary/chat/Chat.tsx @@ -69,11 +69,6 @@ export function ChatScreen({}: StackScreenProps) { } await message.pin() - await currentChannel.update({ name: "Grupa chatowa 23" + Math.random() }) - // const refreshedChannel = await chat.getChannel(currentChannel.id) - // if (refreshedChannel) { - // setCurrentChannel(refreshedChannel) - // } }, [chat, currentChannel, setCurrentChannel] ) @@ -103,18 +98,6 @@ export function ChatScreen({}: StackScreenProps) { onToggleEmoji: handleEmoji, }) - useEffect(() => { - if (!currentChannel) { - return - } - console.log("hello", currentChannel) - const unstream = currentChannel.streamUpdates((ch) => { - console.log("ch", ch) - }) - - return unstream - }, [currentChannel]) - useEffect(() => { if (!giftedChatMappedMessages.length) { return diff --git a/samples/react-native-group-chat/screens/ordinary/pinned-message/PinnedMessage.tsx b/samples/react-native-group-chat/screens/ordinary/pinned-message/PinnedMessage.tsx index bf0aa8e4..df64e873 100644 --- a/samples/react-native-group-chat/screens/ordinary/pinned-message/PinnedMessage.tsx +++ b/samples/react-native-group-chat/screens/ordinary/pinned-message/PinnedMessage.tsx @@ -16,12 +16,23 @@ export function PinnedMessage({}: StackScreenProps { async function init() { if (!chat || !currentChannel) return - setMessage(await currentChannel.getPinnedMessage()) + const refreshedChannel = await chat.getChannel(currentChannel.id) + if (refreshedChannel) { + setMessage(await refreshedChannel.getPinnedMessage()) + } } init() }, [chat, currentChannel]) + useEffect(() => { + const unstream = currentChannel?.streamUpdates(async (channel) => { + setMessage(await channel.getPinnedMessage()) + }) + + return unstream + }, [currentChannel]) + const renderMessageBubble = useCallback( (props: Bubble["props"]) => { if (!message) { From d77c67c01a149e046637e30400ed0cf31b7bdddd Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Tue, 17 Oct 2023 15:10:30 +0200 Subject: [PATCH 7/9] feat(lib): revert one method --- lib/src/entities/membership.ts | 19 +++++++++++++++++++ lib/src/entities/user.ts | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/src/entities/membership.ts b/lib/src/entities/membership.ts index 6eff661b..3328db6d 100644 --- a/lib/src/entities/membership.ts +++ b/lib/src/entities/membership.ts @@ -134,6 +134,25 @@ export class Membership { return this.custom?.lastReadMessageTimetoken } + async setLastReadMessage(message: Message) { + try { + const response = await this.update({ + custom: { ...this.custom, lastReadMessageTimetoken: message.timetoken }, + }) + + await this.chat.emitEvent({ + channel: this.channel.id, + type: "receipt", + method: "signal", + payload: { messageTimetoken: message.timetoken }, + }) + + return response + } catch (error) { + throw error + } + } + async setLastReadMessageTimetoken(timetoken: string) { try { const response = await this.update({ diff --git a/lib/src/entities/user.ts b/lib/src/entities/user.ts index cd8b8e87..cc864098 100644 --- a/lib/src/entities/user.ts +++ b/lib/src/entities/user.ts @@ -54,7 +54,6 @@ export class User { } get active() { - console.log("userid", this.id, new Date().getTime(), this.lastActiveTimestamp) return !!( this.lastActiveTimestamp && new Date().getTime() - this.lastActiveTimestamp <= this.chat.config.storeUserActivityInterval From 77b6fff5a0357f24dda86ee3b85dd7ee6ea26e41 Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Tue, 17 Oct 2023 15:29:17 +0200 Subject: [PATCH 8/9] feat(lib): rm unused async --- lib/src/entities/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/entities/channel.ts b/lib/src/entities/channel.ts index 5274e1fa..6374a588 100644 --- a/lib/src/entities/channel.ts +++ b/lib/src/entities/channel.ts @@ -520,7 +520,7 @@ export class Channel { const freshtimetoken = await this.chat.sdk.time() return await Promise.all( - response.data.map(async (dataPoint) => + response.data.map((dataPoint) => Membership.fromChannelMemberDTO(this.chat, dataPoint, this).setLastReadMessageTimetoken( String(freshtimetoken.timetoken) ) From 20783aaef9f33161315e1bcd55d1219c4f55afa1 Mon Sep 17 00:00:00 2001 From: Piotr Suwala Date: Tue, 17 Oct 2023 15:38:48 +0200 Subject: [PATCH 9/9] feat(lib): simplify one method --- lib/src/entities/channel.ts | 4 ++-- lib/src/entities/membership.ts | 17 +---------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/src/entities/channel.ts b/lib/src/entities/channel.ts index 6374a588..a0f86b9f 100644 --- a/lib/src/entities/channel.ts +++ b/lib/src/entities/channel.ts @@ -517,12 +517,12 @@ export class Channel { }, filter, }) - const freshtimetoken = await this.chat.sdk.time() + const { timetoken } = await this.chat.sdk.time() return await Promise.all( response.data.map((dataPoint) => Membership.fromChannelMemberDTO(this.chat, dataPoint, this).setLastReadMessageTimetoken( - String(freshtimetoken.timetoken) + String(timetoken) ) ) ) diff --git a/lib/src/entities/membership.ts b/lib/src/entities/membership.ts index 3328db6d..c0d12441 100644 --- a/lib/src/entities/membership.ts +++ b/lib/src/entities/membership.ts @@ -135,22 +135,7 @@ export class Membership { } async setLastReadMessage(message: Message) { - try { - const response = await this.update({ - custom: { ...this.custom, lastReadMessageTimetoken: message.timetoken }, - }) - - await this.chat.emitEvent({ - channel: this.channel.id, - type: "receipt", - method: "signal", - payload: { messageTimetoken: message.timetoken }, - }) - - return response - } catch (error) { - throw error - } + return this.setLastReadMessageTimetoken(message.timetoken) } async setLastReadMessageTimetoken(timetoken: string) {