diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index a65743a3e2..87e8c3c307 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -1364,7 +1364,7 @@ export class RoomView extends React.Component { if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) { // For initial threads launch, chat effects are disabled see #19731 if (!ev.isRelation(THREAD_RELATION_TYPE.name)) { - dis.dispatch({ action: `effects.${effect.command}` }); + dis.dispatch({ action: `effects.${effect.command}`, event: ev }); } } }); diff --git a/src/components/views/elements/EffectsOverlay.tsx b/src/components/views/elements/EffectsOverlay.tsx index 76262ad4f0..3e5a5ead60 100644 --- a/src/components/views/elements/EffectsOverlay.tsx +++ b/src/components/views/elements/EffectsOverlay.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. */ import React, { FunctionComponent, useEffect, useRef } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixEvent } from "matrix-js-sdk/src/matrix"; import dis from "../../../dispatcher/dispatcher"; import ICanvasEffect from "../../../effects/ICanvasEffect"; @@ -44,9 +45,10 @@ const EffectsOverlay: FunctionComponent = ({ roomWidth }) => { canvasRef.current.height = UIStore.instance.windowHeight; } }; - const onAction = (payload: { action: string }): void => { + const onAction = (payload: { action: string; event?: MatrixEvent }): void => { const actionPrefix = "effects."; - if (canvasRef.current && payload.action.startsWith(actionPrefix)) { + const isOutdated = isEventOutdated(payload.event); + if (canvasRef.current && payload.action.startsWith(actionPrefix) && !isOutdated) { const effect = payload.action.slice(actionPrefix.length); lazyLoadEffectModule(effect).then((module) => module?.start(canvasRef.current!)); } @@ -88,3 +90,19 @@ const EffectsOverlay: FunctionComponent = ({ roomWidth }) => { }; export default EffectsOverlay; + +// 48 hours +// 48h * 60m * 60s * 1000ms +const OUTDATED_EVENT_THRESHOLD = 48 * 60 * 60 * 1000; + +/** + * Return true if the event is older than 48h. + * @param event + */ +function isEventOutdated(event?: MatrixEvent): boolean { + if (!event) return false; + + const nowTs = Date.now(); + const eventTs = event.getTs(); + return nowTs - eventTs > OUTDATED_EVENT_THRESHOLD; +} diff --git a/test/components/views/elements/EffectsOverlay-test.tsx b/test/components/views/elements/EffectsOverlay-test.tsx new file mode 100644 index 0000000000..48e508181d --- /dev/null +++ b/test/components/views/elements/EffectsOverlay-test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only + * Please see LICENSE files in the repository root for full details. + * + */ + +import React from "react"; +import { render, waitFor } from "@testing-library/react"; + +import dis from "../../../../src/dispatcher/dispatcher"; +import EffectsOverlay from "../../../../src/components/views/elements/EffectsOverlay.tsx"; + +describe("", () => { + let isStarted: boolean; + beforeEach(() => { + isStarted = false; + jest.mock("../../../../src/effects/confetti/index.ts", () => { + return class Confetti { + start = () => { + isStarted = true; + }; + stop = jest.fn(); + }; + }); + }); + + afterEach(() => jest.useRealTimers()); + + it("should render", () => { + const { asFragment } = render(); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should start the confetti effect", async () => { + render(); + dis.dispatch({ action: "effects.confetti" }); + await waitFor(() => expect(isStarted).toBe(true)); + }); + + it("should start the confetti effect when the event is not outdated", async () => { + const eventDate = new Date("2024-09-01"); + const date = new Date("2024-09-02"); + jest.useFakeTimers().setSystemTime(date); + + render(); + dis.dispatch({ action: "effects.confetti", event: { getTs: () => eventDate.getTime() } }); + await waitFor(() => expect(isStarted).toBe(true)); + }); +}); diff --git a/test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap b/test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap new file mode 100644 index 0000000000..222d893e99 --- /dev/null +++ b/test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should render 1`] = ` + + +`;