stream-chat-react-native-core
Version:
The official React Native and Expo components for Stream Chat, a service for building chat applications
104 lines (85 loc) • 3.18 kB
text/typescript
import { useCallback, useEffect, useState } from 'react';
import { Channel, Event, LocalMessage, MessageResponse } from 'stream-chat';
import { useChatContext } from '../../contexts/chatContext/ChatContext';
export enum MessageDeliveryStatus {
NOT_SENT_BY_CURRENT_USER = 'not_sent_by_current_user',
DELIVERED = 'delivered',
READ = 'read',
SENT = 'sent',
}
type MessageDeliveryStatusProps = {
channel: Channel;
lastMessage: LocalMessage;
isReadEventsEnabled: boolean;
};
export const useMessageDeliveryStatus = ({
channel,
lastMessage,
isReadEventsEnabled = true,
}: MessageDeliveryStatusProps) => {
const { client } = useChatContext();
const [status, setStatus] = useState<MessageDeliveryStatus | undefined>(undefined);
const isOwnMessage = useCallback(
(message: LocalMessage | MessageResponse) =>
client.user && message && message.user?.id === client.user.id,
[client],
);
useEffect(() => {
if (!lastMessage) {
setStatus(undefined);
}
if (!isReadEventsEnabled) {
setStatus(MessageDeliveryStatus.NOT_SENT_BY_CURRENT_USER);
return;
}
if (!lastMessage?.created_at || !isOwnMessage(lastMessage)) {
return;
}
const msgRef = {
msgId: lastMessage.id,
timestampMs: new Date(lastMessage.created_at).getTime(),
};
const readerOfMessage = channel.messageReceiptsTracker.readersForMessage(msgRef);
const deliveredForMessage = channel.messageReceiptsTracker.deliveredForMessage(msgRef);
setStatus(
readerOfMessage.length > 1 ||
(readerOfMessage.length === 1 && readerOfMessage[0].id !== client.user?.id)
? MessageDeliveryStatus.READ
: deliveredForMessage.length > 1 ||
(deliveredForMessage.length === 1 && deliveredForMessage[0].id !== client.user?.id)
? MessageDeliveryStatus.DELIVERED
: MessageDeliveryStatus.SENT,
);
}, [channel, client.user?.id, isOwnMessage, isReadEventsEnabled, lastMessage]);
useEffect(() => {
const handleMessageNew = (event: Event) => {
// the last message is not mine, so do not show the delivery status
if (event.message && !isOwnMessage(event.message)) {
return setStatus(undefined);
}
return setStatus(MessageDeliveryStatus.SENT);
};
const { unsubscribe } = channel.on('message.new', handleMessageNew);
return unsubscribe;
}, [channel, isOwnMessage]);
useEffect(() => {
if (!isOwnMessage(lastMessage)) return;
const handleMessageDelivered = (event: Event) => {
if (
event.user?.id !== client.user?.id &&
lastMessage &&
lastMessage.id === event.last_delivered_message_id
)
setStatus(MessageDeliveryStatus.DELIVERED);
};
const handleMarkRead = (event: Event) => {
if (event.user?.id !== client.user?.id) setStatus(MessageDeliveryStatus.READ);
};
const listeners = [
channel.on('message.delivered', handleMessageDelivered),
channel.on('message.read', handleMarkRead),
];
return () => listeners.forEach((l) => l.unsubscribe());
}, [channel, client, isOwnMessage, lastMessage]);
return { status };
};