mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-20 20:49:20 +00:00
Compare commits
4 Commits
v0.23.0
...
hs/hand-ra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d685bc44e | ||
|
|
7a05ad9f79 | ||
|
|
3b272181ae | ||
|
|
a62e884e8c |
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { render } from "@testing-library/react";
|
||||
import { findByRole, getByRole, render } from "@testing-library/react";
|
||||
import { act, FC } from "react";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { RoomEvent } from "matrix-js-sdk/src/matrix";
|
||||
@@ -43,7 +43,7 @@ const TestComponent: FC = () => {
|
||||
<div>
|
||||
<ul>
|
||||
{Object.entries(raisedHands).map(([userId, date]) => (
|
||||
<li key={userId}>
|
||||
<li role="listitem" key={userId}>
|
||||
<span>{userId}</span>
|
||||
<time>{date.getTime()}</time>
|
||||
</li>
|
||||
@@ -106,12 +106,12 @@ describe("useReactions", () => {
|
||||
createHandRaisedReaction(memberEventAlice, membership),
|
||||
]);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { queryByRole } = render(
|
||||
const { findByRole } = render(
|
||||
<TestReactionsWrapper rtcSession={rtcSession}>
|
||||
<TestComponent />
|
||||
</TestReactionsWrapper>,
|
||||
);
|
||||
expect(queryByRole("list")?.children).to.have.lengthOf(1);
|
||||
expect(findByRole("listitem")).toBeTruthy();
|
||||
});
|
||||
// If the membership event changes for a user, we want to remove
|
||||
// the raised hand event.
|
||||
@@ -120,12 +120,12 @@ describe("useReactions", () => {
|
||||
createHandRaisedReaction(memberEventAlice, membership),
|
||||
]);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { queryByRole } = render(
|
||||
const { findByRole, queryByRole } = render(
|
||||
<TestReactionsWrapper rtcSession={rtcSession}>
|
||||
<TestComponent />
|
||||
</TestReactionsWrapper>,
|
||||
);
|
||||
expect(queryByRole("list")?.children).to.have.lengthOf(1);
|
||||
expect(findByRole("listitem")).toBeTruthy();
|
||||
act(() => rtcSession.testRemoveMember(memberUserIdAlice));
|
||||
expect(queryByRole("list")?.children).to.have.lengthOf(0);
|
||||
});
|
||||
@@ -134,12 +134,12 @@ describe("useReactions", () => {
|
||||
createHandRaisedReaction(memberEventAlice, membership),
|
||||
]);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { queryByRole } = render(
|
||||
const { queryByRole, findByRole } = render(
|
||||
<TestReactionsWrapper rtcSession={rtcSession}>
|
||||
<TestComponent />
|
||||
</TestReactionsWrapper>,
|
||||
);
|
||||
expect(queryByRole("list")?.children).to.have.lengthOf(1);
|
||||
expect(findByRole("listitem")).toBeTruthy();
|
||||
// Simulate leaving and rejoining
|
||||
act(() => {
|
||||
rtcSession.testRemoveMember(memberUserIdAlice);
|
||||
|
||||
@@ -106,6 +106,7 @@ export const ReactionsProvider = ({
|
||||
);
|
||||
|
||||
const addRaisedHand = useCallback((userId: string, info: RaisedHandInfo) => {
|
||||
logger.info(`Adding raised hand for ${userId}`);
|
||||
setRaisedHands((prevRaisedHands) => ({
|
||||
...prevRaisedHands,
|
||||
[userId]: info,
|
||||
@@ -113,6 +114,7 @@ export const ReactionsProvider = ({
|
||||
}, []);
|
||||
|
||||
const removeRaisedHand = useCallback((userId: string) => {
|
||||
logger.info(`Removing raised hand for ${userId}`);
|
||||
setRaisedHands(
|
||||
({ [userId]: _removed, ...remainingRaisedHands }) => remainingRaisedHands,
|
||||
);
|
||||
@@ -121,16 +123,26 @@ export const ReactionsProvider = ({
|
||||
// This effect will check the state whenever the membership of the session changes.
|
||||
useEffect(() => {
|
||||
// Fetches the first reaction for a given event.
|
||||
const getLastReactionEvent = (
|
||||
const getLastReactionEvent = async (
|
||||
eventId: string,
|
||||
expectedSender: string,
|
||||
): MatrixEvent | undefined => {
|
||||
): Promise<MatrixEvent | undefined> => {
|
||||
const relations = room.relations.getChildEventsForEvent(
|
||||
eventId,
|
||||
RelationType.Annotation,
|
||||
EventType.Reaction,
|
||||
);
|
||||
const allEvents = relations?.getRelations() ?? [];
|
||||
let allEvents = relations?.getRelations() ?? [];
|
||||
// If we found no relations for this event, fetch via fetchRelations.
|
||||
if (allEvents.length === 0) {
|
||||
const res = await room.client.fetchRelations(
|
||||
room.roomId,
|
||||
eventId,
|
||||
RelationType.Annotation,
|
||||
EventType.Reaction,
|
||||
);
|
||||
allEvents = res.chunk.map((e) => new MatrixEvent(e));
|
||||
}
|
||||
return allEvents.find(
|
||||
(reaction) =>
|
||||
reaction.event.sender === expectedSender &&
|
||||
@@ -160,18 +172,26 @@ export const ReactionsProvider = ({
|
||||
// was raised, reset.
|
||||
removeRaisedHand(m.sender);
|
||||
}
|
||||
const reaction = getLastReactionEvent(m.eventId, m.sender);
|
||||
if (reaction) {
|
||||
const eventId = reaction?.getId();
|
||||
if (!eventId) {
|
||||
continue;
|
||||
}
|
||||
addRaisedHand(m.sender, {
|
||||
membershipEventId: m.eventId,
|
||||
reactionEventId: eventId,
|
||||
time: new Date(reaction.localTimestamp),
|
||||
getLastReactionEvent(m.eventId, m.sender)
|
||||
.then((reaction) => {
|
||||
if (reaction) {
|
||||
const eventId = reaction.getId();
|
||||
if (!eventId) {
|
||||
return;
|
||||
}
|
||||
addRaisedHand(m.sender!, {
|
||||
membershipEventId: m.eventId!,
|
||||
reactionEventId: eventId,
|
||||
time: new Date(reaction.localTimestamp),
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((ex) => {
|
||||
logger.warn(
|
||||
`Failed to fetch reaction for member ${m.sender} (${m.eventId})`,
|
||||
ex,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Ignoring raisedHands here because we don't want to trigger each time the raised
|
||||
// hands set is updated.
|
||||
@@ -307,8 +327,8 @@ export const ReactionsProvider = ({
|
||||
return (): void => {
|
||||
room.off(MatrixRoomEvent.Timeline, handleReactionEvent);
|
||||
room.off(MatrixRoomEvent.Redaction, handleReactionEvent);
|
||||
room.client.off(MatrixEventEvent.Decrypted, handleReactionEvent);
|
||||
room.off(MatrixRoomEvent.LocalEchoUpdated, handleReactionEvent);
|
||||
room.client.off(MatrixEventEvent.Decrypted, handleReactionEvent);
|
||||
reactionTimeouts.forEach((t) => clearTimeout(t));
|
||||
// If we're clearing timeouts, we also clear all reactions.
|
||||
setReactions({});
|
||||
|
||||
@@ -139,6 +139,7 @@ export class MockRoom extends EventEmitter {
|
||||
return Promise.resolve({ event_id: randomUUID() });
|
||||
},
|
||||
decryptEventIfNeeded: async () => {},
|
||||
fetchRelations: async () => Promise.resolve({ chunk: [] }),
|
||||
on() {
|
||||
return this;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user