diff --git a/packages/shared-components/src/audio/Clock/Clock.tsx b/packages/shared-components/src/audio/Clock/Clock.tsx index 176044269d..7b8d9496cb 100644 --- a/packages/shared-components/src/audio/Clock/Clock.tsx +++ b/packages/shared-components/src/audio/Clock/Clock.tsx @@ -5,13 +5,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import React, { type HTMLProps } from "react"; +import React, { type JSX, type HTMLProps, useMemo } from "react"; import { Temporal } from "temporal-polyfill"; import classNames from "classnames"; import { formatSeconds } from "../../utils/DateUtils"; export interface Props extends Pick, "aria-live" | "role" | "className"> { + /** + * The number of seconds to display. + */ seconds: number; } @@ -19,33 +22,39 @@ export interface Props extends Pick, "aria-live" | "r * Clock which represents time periods rather than absolute time. * Simply converts seconds using formatSeconds(). * Note that in this case hours will not be displayed, making it possible to see "82:29". + * + * @example + * ```tsx + * + * ``` */ -export class Clock extends React.Component { - public shouldComponentUpdate(nextProps: Readonly): boolean { - const currentFloor = Math.floor(this.props.seconds); - const nextFloor = Math.floor(nextProps.seconds); - return currentFloor !== nextFloor; - } +export function Clock({ seconds, className, ...rest }: Props): JSX.Element { + // Memoize current second to avoid recalculating the duration when seconds changes slightly (e.g. 1.2 -> 1.3) + const currentSecond = useMemo(() => Math.floor(seconds), [seconds]); + const duration = useMemo(() => calculateDuration(currentSecond), [currentSecond]); - private calculateDuration(seconds: number): string | undefined { - if (isNaN(seconds)) return undefined; - return new Temporal.Duration(0, 0, 0, 0, 0, 0, Math.round(seconds)) - .round({ smallestUnit: "seconds", largestUnit: "hours" }) - .toString(); - } - - public render(): React.ReactNode { - const { seconds, role } = this.props; - return ( - - ); - } + return ( + + ); +} + +/** + * Calculates an ISO 8601 duration string from seconds. + * @param seconds + * @returns ISO 8601 duration string or undefined if input is NaN + */ +function calculateDuration(seconds: number): string | undefined { + // This shouldn't happen but it's in the original implementation + if (isNaN(seconds)) return undefined; + + return new Temporal.Duration(0, 0, 0, 0, 0, 0, Math.round(seconds)) + .round({ smallestUnit: "seconds", largestUnit: "hours" }) + .toString(); }