bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/common/remaining-time/component.tsx
2024-06-11 13:10:04 -03:00

125 lines
3.8 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
import humanizeSeconds from '/imports/utils/humanizeSeconds';
import { Text, Time } from './styles';
import { notify } from '/imports/ui/services/notification';
import useTimeSync from '/imports/ui/core/local-states/useTimeSync';
type intlMsg = {
id: string;
description?: string;
};
interface RemainingTimeProps {
referenceStartedTime: number;
durationInSeconds: number;
durationLabel: intlMsg;
isBreakout: boolean;
boldText: boolean;
endingLabel?: intlMsg;
alertLabel?: intlMsg;
}
let lastAlertTime: number | null = null;
const RemainingTime: React.FC<RemainingTimeProps> = (props) => {
const {
referenceStartedTime,
durationInSeconds,
durationLabel,
endingLabel = undefined,
alertLabel = undefined,
isBreakout,
boldText,
} = props;
const intl = useIntl();
const [timeSync] = useTimeSync();
const timeRemainingInterval = React.useRef<ReturnType<typeof setTimeout>>();
const [remainingTime, setRemainingTime] = useState<number>(-1);
const currentDate: Date = new Date();
const adjustedCurrent: Date = new Date(currentDate.getTime() + timeSync);
const calculateRemainingTime = () => {
const durationInMilliseconds = durationInSeconds * 1000;
const adjustedCurrentTime = adjustedCurrent.getTime();
return Math.floor(((referenceStartedTime + durationInMilliseconds) - adjustedCurrentTime) / 1000);
};
useEffect(() => {
if (remainingTime && durationInSeconds) {
if (durationInSeconds > 0 && timeRemainingInterval && referenceStartedTime) {
setRemainingTime(calculateRemainingTime());
}
clearInterval(timeRemainingInterval.current);
const remainingMillisecondsDiff = (
(referenceStartedTime + (durationInSeconds * 60000)) - adjustedCurrent.getTime()
) % 1000;
timeRemainingInterval.current = setInterval(() => {
setRemainingTime((currentTime) => currentTime - 1);
}, remainingMillisecondsDiff === 0 ? 1000 : remainingMillisecondsDiff);
}
return () => {
clearInterval(timeRemainingInterval.current);
};
}, [remainingTime, durationInSeconds]);
const meetingTimeMessage = React.useRef<string>('');
if (remainingTime >= 0 && timeRemainingInterval) {
if (remainingTime > 0) {
const APP_SETTINGS = window.meetingClientSettings.public.app;
const REMAINING_TIME_ALERT_THRESHOLD_ARRAY: number[] = APP_SETTINGS.remainingTimeAlertThresholdArray;
const alertsInSeconds = REMAINING_TIME_ALERT_THRESHOLD_ARRAY.map((item) => item * 60);
if (alertsInSeconds.includes(remainingTime) && remainingTime !== lastAlertTime && alertLabel) {
const timeInMinutes = remainingTime / 60;
const msg = { id: `${alertLabel.id}${timeInMinutes === 1 ? 'Singular' : 'Plural'}` };
const alertMessage = intl.formatMessage(msg, { 0: timeInMinutes });
lastAlertTime = remainingTime;
notify(alertMessage, 'info', 'rooms');
}
meetingTimeMessage.current = intl.formatMessage(durationLabel, { 0: humanizeSeconds(remainingTime) });
if (isBreakout) {
return (
<span data-test="timeRemaining">
{meetingTimeMessage.current}
</span>
);
}
} else {
clearInterval(timeRemainingInterval.current);
if (endingLabel) meetingTimeMessage.current = intl.formatMessage(endingLabel);
}
}
if (boldText) {
const words = meetingTimeMessage.current.split(' ');
const time = words.pop();
const text = words.join(' ');
return (
<span data-test="timeRemaining">
<Text>{text}</Text>
<br />
<Time data-test="breakoutRemainingTime">{time}</Time>
</span>
);
}
return (
<span data-test="timeRemaining">
{meetingTimeMessage.current}
</span>
);
};
export default RemainingTime;