Add some explanation comments.

This commit is contained in:
Half-Shot
2024-10-29 16:57:06 +00:00
parent ff7da135ca
commit a45b01dc00
3 changed files with 24 additions and 11 deletions

View File

@@ -21,6 +21,7 @@ export function RaisedHandIndicator({
}): ReactNode { }): ReactNode {
const [raisedHandDuration, setRaisedHandDuration] = useState(""); const [raisedHandDuration, setRaisedHandDuration] = useState("");
// This effect creates a simple timer effect.
useEffect(() => { useEffect(() => {
if (!raisedHandTime || !showTimer) { if (!raisedHandTime || !showTimer) {
return; return;

View File

@@ -26,6 +26,13 @@ import { randomUUID } from "crypto";
import { ReactionsProvider, useReactions } from "./useReactions"; import { ReactionsProvider, useReactions } from "./useReactions";
/**
* Test explanation.
* This test suite checks that the useReactions hook appropriately reacts
* to new reactions, redactions and membership changesin the room. There is
* a large amount of test structure used to construct a mock environment.
*/
const memberUserIdAlice = "@alice:example.org"; const memberUserIdAlice = "@alice:example.org";
const memberEventAlice = "$membership-alice:example.org"; const memberEventAlice = "$membership-alice:example.org";
const memberUserIdBob = "@bob:example.org"; const memberUserIdBob = "@bob:example.org";
@@ -198,7 +205,7 @@ describe("useReactions", () => {
rerender(<TestComponentWrapper rtcSession={rtcSession} />); rerender(<TestComponentWrapper rtcSession={rtcSession} />);
expect(queryByRole("list")?.children).to.have.lengthOf(0); expect(queryByRole("list")?.children).to.have.lengthOf(0);
}); });
test("handles loading events from cold", () => { test("handles loading prior raised hand events", () => {
const room = new MockRoom([createReaction(memberEventAlice)]); const room = new MockRoom([createReaction(memberEventAlice)]);
const rtcSession = new MockRTCSession(room); const rtcSession = new MockRTCSession(room);
const { queryByRole } = render( const { queryByRole } = render(
@@ -206,6 +213,8 @@ describe("useReactions", () => {
); );
expect(queryByRole("list")?.children).to.have.lengthOf(1); expect(queryByRole("list")?.children).to.have.lengthOf(1);
}); });
// If the membership event changes for a user, we want to remove
// the raised hand event.
test("will remove reaction when a member leaves the call", () => { test("will remove reaction when a member leaves the call", () => {
const room = new MockRoom([createReaction(memberEventAlice)]); const room = new MockRoom([createReaction(memberEventAlice)]);
const rtcSession = new MockRTCSession(room); const rtcSession = new MockRTCSession(room);
@@ -224,6 +233,7 @@ describe("useReactions", () => {
<TestComponentWrapper rtcSession={rtcSession} />, <TestComponentWrapper rtcSession={rtcSession} />,
); );
expect(queryByRole("list")?.children).to.have.lengthOf(1); expect(queryByRole("list")?.children).to.have.lengthOf(1);
// Simulate leaving and rejoining
rtcSession.testRemoveMember(memberUserIdAlice); rtcSession.testRemoveMember(memberUserIdAlice);
rtcSession.testAddMember(memberUserIdAlice); rtcSession.testAddMember(memberUserIdAlice);
rerender(<TestComponentWrapper rtcSession={rtcSession} />); rerender(<TestComponentWrapper rtcSession={rtcSession} />);

View File

@@ -72,6 +72,7 @@ export const ReactionsProvider = ({
clientState?.state === "valid" && clientState.supportedFeatures.reactions; clientState?.state === "valid" && clientState.supportedFeatures.reactions;
const room = rtcSession.room; const room = rtcSession.room;
// Calculate our own reaction event.
const myReactionId = useMemo((): string | null => { const myReactionId = useMemo((): string | null => {
const myUserId = room.client.getUserId(); const myUserId = room.client.getUserId();
if (myUserId) { if (myUserId) {
@@ -80,6 +81,15 @@ export const ReactionsProvider = ({
return null; return null;
}, [raisedHands, room]); }, [raisedHands, room]);
// Reduce the data down for the consumers.
const resultRaisedHands = useMemo(
() =>
Object.fromEntries(
Object.entries(raisedHands).map(([uid, data]) => [uid, data.time]),
),
[raisedHands],
);
const addRaisedHand = useCallback( const addRaisedHand = useCallback(
(userId: string, info: RaisedHandInfo) => { (userId: string, info: RaisedHandInfo) => {
setRaisedHands({ setRaisedHands({
@@ -98,7 +108,7 @@ export const ReactionsProvider = ({
[raisedHands], [raisedHands],
); );
// Load any existing reactions. // This effect will check the state whenever the membership of the session changes.
useEffect(() => { useEffect(() => {
const getLastReactionEvent = (eventId: string): MatrixEvent | undefined => { const getLastReactionEvent = (eventId: string): MatrixEvent | undefined => {
const relations = room.relations.getChildEventsForEvent( const relations = room.relations.getChildEventsForEvent(
@@ -148,6 +158,7 @@ export const ReactionsProvider = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [room, memberships]); }, [room, memberships]);
// This effect handles any *live* reaction/redactions in the room.
useEffect(() => { useEffect(() => {
const handleReactionEvent = (event: MatrixEvent): void => { const handleReactionEvent = (event: MatrixEvent): void => {
const sender = event.getSender(); const sender = event.getSender();
@@ -201,15 +212,6 @@ export const ReactionsProvider = ({
}; };
}, [room, addRaisedHand, removeRaisedHand, memberships, raisedHands]); }, [room, addRaisedHand, removeRaisedHand, memberships, raisedHands]);
// Reduce the data down for the consumers.
const resultRaisedHands = useMemo(
() =>
Object.fromEntries(
Object.entries(raisedHands).map(([uid, data]) => [uid, data.time]),
),
[raisedHands],
);
return ( return (
<ReactionsContext.Provider <ReactionsContext.Provider
value={{ value={{