From a23d256fb6bf029c840318d695cfbf54aa193cfa Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 28 Oct 2024 12:32:33 +0000 Subject: [PATCH] Refactor raised hand indicator and add tests. --- src/reactions/RaisedHandIndicator.module.css | 39 ++++++++++++++++ src/reactions/RaisedHandIndicator.test.tsx | 36 +++++++++++++++ src/reactions/RaisedHandIndicator.tsx | 44 +++++++++++++++++++ .../RaisedHandIndicator.test.tsx.snap | 41 +++++++++++++++++ src/tile/MediaView.module.css | 40 ----------------- src/tile/MediaView.tsx | 32 +------------- 6 files changed, 162 insertions(+), 70 deletions(-) create mode 100644 src/reactions/RaisedHandIndicator.module.css create mode 100644 src/reactions/RaisedHandIndicator.test.tsx create mode 100644 src/reactions/RaisedHandIndicator.tsx create mode 100644 src/reactions/__snapshots__/RaisedHandIndicator.test.tsx.snap diff --git a/src/reactions/RaisedHandIndicator.module.css b/src/reactions/RaisedHandIndicator.module.css new file mode 100644 index 00000000..b5dd6e49 --- /dev/null +++ b/src/reactions/RaisedHandIndicator.module.css @@ -0,0 +1,39 @@ +.raisedHandWidget { + display: flex; + background-color: var(--cpd-color-bg-subtle-primary); + border-radius: var(--cpd-radius-pill-effect); + color: var(--cpd-color-icon-secondary); + border: 1px solid var(--cpd-color-yellow-1200); +} + +.raisedHandWidget > p { + padding: var(--cpd-space-2x); + margin-top: auto; + margin-bottom: auto; + width: 4em; +} + +.raisedHand { + margin: var(--cpd-space-2x); + padding: var(--cpd-space-2x); + padding-block: var(--cpd-space-2x); + color: var(--cpd-color-icon-secondary); + background-color: var(--cpd-color-icon-secondary); + display: flex; + align-items: center; + border-radius: var(--cpd-radius-pill-effect); + user-select: none; + overflow: hidden; + box-shadow: var(--small-drop-shadow); + box-sizing: border-box; + max-inline-size: 100%; + max-width: fit-content; +} + +.raisedHand > span { + width: var(--cpd-space-8x); + height: var(--cpd-space-8x); + display: inline-block; + text-align: center; + font-size: 22px; +} diff --git a/src/reactions/RaisedHandIndicator.test.tsx b/src/reactions/RaisedHandIndicator.test.tsx new file mode 100644 index 00000000..8463a625 --- /dev/null +++ b/src/reactions/RaisedHandIndicator.test.tsx @@ -0,0 +1,36 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only +Please see LICENSE in the repository root for full details. +*/ + +import { describe, expect, test } from "vitest"; +import { render, configure } from "@testing-library/react"; + +import { RaisedHandIndicator } from "./RaisedHandIndicator"; + +configure({ + defaultHidden: true, +}); + +describe("RaisedHandIndicator", () => { + test("renders nothing when no hand has been raised", async () => { + const { container } = render(); + expect(container.firstChild).toBeNull(); + }); + test("renders an indicator when a hand has been raised", async () => { + const dateTime = new Date(); + const { container } = render( + , + ); + expect(container.firstChild).toMatchSnapshot(); + }); + test("renders an indicator when a hand has been raised with the expected time", async () => { + const dateTime = new Date(new Date().getTime() - 60000); + const { container } = render( + , + ); + expect(container.firstChild).toMatchSnapshot(); + }); +}); diff --git a/src/reactions/RaisedHandIndicator.tsx b/src/reactions/RaisedHandIndicator.tsx new file mode 100644 index 00000000..012fa571 --- /dev/null +++ b/src/reactions/RaisedHandIndicator.tsx @@ -0,0 +1,44 @@ +import { useEffect, useState } from "react"; +import styles from "./RaisedHandIndicator.module.css"; + +export function RaisedHandIndicator({ + raisedHandTime, +}: { + raisedHandTime?: Date; +}) { + const [raisedHandDuration, setRaisedHandDuration] = useState(""); + + useEffect(() => { + if (!raisedHandTime) { + return; + } + const calculateTime = () => { + const totalSeconds = Math.ceil( + (new Date().getTime() - raisedHandTime.getTime()) / 1000, + ); + const seconds = totalSeconds % 60; + const minutes = Math.floor(totalSeconds / 60); + setRaisedHandDuration( + `${minutes < 10 ? "0" : ""}${minutes}:${seconds < 10 ? "0" : ""}${seconds}`, + ); + }; + const to = setInterval(calculateTime, 1000); + calculateTime(); + return (): void => clearInterval(to); + }, [setRaisedHandDuration, raisedHandTime]); + + if (raisedHandTime) { + return ( +
+
+ + ✋ + +
+

{raisedHandDuration}

+
+ ); + } + + return null; +} diff --git a/src/reactions/__snapshots__/RaisedHandIndicator.test.tsx.snap b/src/reactions/__snapshots__/RaisedHandIndicator.test.tsx.snap new file mode 100644 index 00000000..67719949 --- /dev/null +++ b/src/reactions/__snapshots__/RaisedHandIndicator.test.tsx.snap @@ -0,0 +1,41 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`RaisedHandIndicator > renders an indicator when a hand has been raised 1`] = ` +
+
+ + ✋ + +
+

+ 00:01 +

+
+`; + +exports[`RaisedHandIndicator > renders an indicator when a hand has been raised with the expected time 1`] = ` +
+
+ + ✋ + +
+

+ 01:01 +

+
+`; diff --git a/src/tile/MediaView.module.css b/src/tile/MediaView.module.css index 2dde20a7..c94c1298 100644 --- a/src/tile/MediaView.module.css +++ b/src/tile/MediaView.module.css @@ -90,46 +90,6 @@ unconditionally select the container so we can use cqmin units */ place-items: start; } -.raisedHandWidget { - display: flex; - background-color: var(--cpd-color-bg-subtle-primary); - border-radius: var(--cpd-radius-pill-effect); - color: var(--cpd-color-icon-secondary); - border: 1px solid var(--cpd-color-yellow-1200); -} - -.raisedHandWidget > p { - padding: var(--cpd-space-2x); - margin-top: auto; - margin-bottom: auto; - width: 4em; -} - -.raisedHand { - margin: var(--cpd-space-2x); - padding: var(--cpd-space-2x); - padding-block: var(--cpd-space-2x); - color: var(--cpd-color-icon-secondary); - background-color: var(--cpd-color-icon-secondary); - display: flex; - align-items: center; - border-radius: var(--cpd-radius-pill-effect); - user-select: none; - overflow: hidden; - box-shadow: var(--small-drop-shadow); - box-sizing: border-box; - max-inline-size: 100%; - max-width: fit-content; -} - -.raisedHand > span { - width: var(--cpd-space-8x); - height: var(--cpd-space-8x); - display: inline-block; - text-align: center; - font-size: 22px; -} - .raisedHandBorder { border: var(--cpd-space-1x) solid var(--cpd-color-yellow-1200); } diff --git a/src/tile/MediaView.tsx b/src/tile/MediaView.tsx index 85bb79fd..41a3bdc1 100644 --- a/src/tile/MediaView.tsx +++ b/src/tile/MediaView.tsx @@ -23,6 +23,7 @@ import { ErrorIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import styles from "./MediaView.module.css"; import { Avatar } from "../Avatar"; +import { RaisedHandIndicator } from "../reactions/RaisedHandIndicator"; interface Props extends ComponentProps { className?: string; @@ -64,26 +65,6 @@ export const MediaView = forwardRef( ) => { const { t } = useTranslation(); - const [raisedHandDuration, setRaisedHandDuration] = useState(""); - - useEffect(() => { - if (!raisedHandTime) { - return; - } - setRaisedHandDuration("00:00"); - const to = setInterval(() => { - const totalSeconds = Math.ceil( - (new Date().getTime() - raisedHandTime.getTime()) / 1000, - ); - const seconds = totalSeconds % 60; - const minutes = Math.floor(totalSeconds / 60); - setRaisedHandDuration( - `${minutes < 10 ? "0" : ""}${minutes}:${seconds < 10 ? "0" : ""}${seconds}`, - ); - }, 1000); - return (): void => clearInterval(to); - }, [setRaisedHandDuration, raisedHandTime]); - return ( ( )}
- {raisedHandTime && ( -
-
- - ✋ - -
-

{raisedHandDuration}

-
- )} +
{nameTagLeadingIcon}