vojo/src/app/hooks/useMessageStatus.ts

75 lines
2.4 KiB
TypeScript

import { useEffect, useState } from 'react';
import { MatrixEvent, Room, RoomEvent, RoomEventHandlerMap, EventStatus } from 'matrix-js-sdk';
import { useMatrixClient } from './useMatrixClient';
export enum MessageDeliveryStatus {
Sending = 'sending',
Sent = 'sent',
Read = 'read',
}
function getDeliveryStatus(
room: Room,
mEvent: MatrixEvent,
myUserId: string
): MessageDeliveryStatus | null {
if (mEvent.getSender() !== myUserId) return null;
const { status } = mEvent;
if (
status === EventStatus.SENDING ||
status === EventStatus.ENCRYPTING ||
status === EventStatus.QUEUED
) {
return MessageDeliveryStatus.Sending;
}
if (status === EventStatus.NOT_SENT || status === EventStatus.CANCELLED) return null;
const eventId = mEvent.getId();
if (!eventId || !eventId.startsWith('$')) return MessageDeliveryStatus.Sending;
const members = room.getMembers();
const otherMembers = members.filter((m) => m.userId !== myUserId && m.membership !== 'invite');
const hasReader = otherMembers.some((member) => room.hasUserReadEvent(member.userId, eventId));
if (hasReader) return MessageDeliveryStatus.Read;
return MessageDeliveryStatus.Sent;
}
export function useMessageStatus(room: Room, mEvent: MatrixEvent): MessageDeliveryStatus | null {
const mx = useMatrixClient();
const myUserId = mx.getSafeUserId();
const isOwnMessage = mEvent.getSender() === myUserId;
const [status, setStatus] = useState<MessageDeliveryStatus | null>(() =>
getDeliveryStatus(room, mEvent, myUserId)
);
useEffect(() => {
if (!isOwnMessage) return undefined;
setStatus(getDeliveryStatus(room, mEvent, myUserId));
const handleReceipt: RoomEventHandlerMap[RoomEvent.Receipt] = (_event, r) => {
if (r.roomId !== room.roomId) return;
setStatus(getDeliveryStatus(room, mEvent, myUserId));
};
const handleLocalEcho: RoomEventHandlerMap[RoomEvent.LocalEchoUpdated] = (event, r) => {
if (r.roomId !== room.roomId) return;
if (event.getId() !== mEvent.getId()) return;
setStatus(getDeliveryStatus(room, mEvent, myUserId));
};
room.on(RoomEvent.Receipt, handleReceipt);
room.on(RoomEvent.LocalEchoUpdated, handleLocalEcho);
return () => {
room.removeListener(RoomEvent.Receipt, handleReceipt);
room.removeListener(RoomEvent.LocalEchoUpdated, handleLocalEcho);
};
}, [room, mEvent, myUserId, isOwnMessage]);
return status;
}