Fix livestream countdown i18n

Ticket: 1228

## Code changes
- Pass through `getTimeAgoStr` so that the value gets localized.
- Pass the simpler `number` around instead of the `moment` object for better memoization.

## Notable differences
Due to how `getTimeAgoStr` is written, we now get to see the time actually counting down, vs "in a few seconds" currently in production.  I think the counting-down behavior was the original intentional, since a 1s timer was used (otherwise, a 1-minute timer could be used) ... or maybe not since streams may not start on the dot.
This commit is contained in:
infinite-persistence 2022-03-31 15:21:28 +08:00 committed by Thomas Zarebczan
parent 321a6901b4
commit 3b98f73a0f
4 changed files with 41 additions and 30 deletions

View file

@ -30,7 +30,7 @@ type Props = {
claim: ?StreamClaim,
hideComments: boolean,
isCurrentClaimLive: boolean,
release: any,
releaseTimeMs: number,
showLivestream: boolean,
showScheduledInfo: boolean,
uri: string,
@ -44,7 +44,7 @@ export default function LivestreamLayout(props: Props) {
claim,
hideComments,
isCurrentClaimLive,
release,
releaseTimeMs,
showLivestream,
showScheduledInfo,
uri,
@ -72,7 +72,7 @@ export default function LivestreamLayout(props: Props) {
<div className={PRIMARY_PLAYER_WRAPPER_CLASS}>
<FileRenderInitiator
uri={claim.canonical_url}
customAction={showScheduledInfo && <LivestreamScheduledInfo release={release} />}
customAction={showScheduledInfo && <LivestreamScheduledInfo releaseTimeMs={releaseTimeMs} />}
/>
</div>

View file

@ -5,29 +5,36 @@ import * as ICONS from 'constants/icons';
import Icon from 'component/common/icon';
import moment from 'moment';
import 'scss/component/livestream-scheduled-info.scss';
import I18nMessage from 'component/i18nMessage';
import { getTimeAgoStr } from 'util/time';
type Props = {
release: any,
releaseTimeMs: number,
};
export default function LivestreamScheduledInfo(props: Props) {
const { release } = props;
const [startDateFromNow, setStartDateFromNow] = useState(release.fromNow());
const { releaseTimeMs } = props;
const [startDateFromNow, setStartDateFromNow] = useState('');
const [inPast, setInPast] = useState('pending');
useEffect(() => {
const calcTime = () => {
setStartDateFromNow(release.fromNow());
setInPast(release.isBefore(moment()));
};
calcTime();
const intervalId = setInterval(calcTime, 1000);
return () => {
clearInterval(intervalId);
};
}, [release]);
const zeroDurationStr = '---';
const timeAgoStr = getTimeAgoStr(releaseTimeMs, true, true, zeroDurationStr);
const startDate = release.format('MMMM Do, h:mm a');
if (timeAgoStr === zeroDurationStr) {
setInPast(true);
} else {
setStartDateFromNow(timeAgoStr);
setInPast(releaseTimeMs < Date.now());
}
};
const intervalId = setInterval(calcTime, 1000);
return () => clearInterval(intervalId);
}, [releaseTimeMs]);
const startDate = moment(releaseTimeMs).format('MMMM Do, h:mm a');
return (
inPast !== 'pending' && (
@ -36,7 +43,7 @@ export default function LivestreamScheduledInfo(props: Props) {
<p className={'livestream-scheduled__time'}>
{!inPast && (
<span>
<span>{__('Live %time_date%', { time_date: startDateFromNow })}</span>
<I18nMessage tokens={{ time_date: startDateFromNow }}>Live %time_date%</I18nMessage>
<br />
<span className={'livestream-scheduled__date'}>{startDate}</span>
</span>

View file

@ -59,12 +59,11 @@ export default function LivestreamPage(props: Props) {
const isCurrentClaimLive = isChannelBroadcasting && activeLivestreamForChannel.claimId === claimId;
const livestreamChannelId = channelClaimId || '';
// $FlowFixMe
const release = moment.unix(claim.value.release_time);
const releaseTime: moment = moment.unix(claim?.value?.release_time || 0);
const stringifiedClaim = JSON.stringify(claim);
React.useEffect(() => {
// TODO: This should not be needed one we unify the livestream player (?)
// TODO: This should not be needed once we unify the livestream player (?)
analytics.playerLoadedEvent('livestream', false);
}, []);
@ -88,10 +87,10 @@ export default function LivestreamPage(props: Props) {
}, [channelUrl, claim, doCommentSocketConnect, uri]);
const claimReleaseStartingSoonStatic = () =>
release.isBetween(moment(), moment().add(LIVESTREAM_STARTS_SOON_BUFFER, 'minutes'));
releaseTime.isBetween(moment(), moment().add(LIVESTREAM_STARTS_SOON_BUFFER, 'minutes'));
const claimReleaseStartedRecentlyStatic = () =>
release.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment());
releaseTime.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment());
// Find out current channels status + active live claim every 30 seconds (or 15 if not live)
const fasterPoll = !isCurrentClaimLive && (claimReleaseStartingSoonStatic() || claimReleaseStartedRecentlyStatic());
@ -105,14 +104,14 @@ export default function LivestreamPage(props: Props) {
React.useEffect(() => {
if (!isInitialized) return;
const claimReleaseInFuture = () => release.isAfter();
const claimReleaseInPast = () => release.isBefore();
const claimReleaseInFuture = () => releaseTime.isAfter();
const claimReleaseInPast = () => releaseTime.isBefore();
const claimReleaseStartingSoon = () =>
release.isBetween(moment(), moment().add(LIVESTREAM_STARTS_SOON_BUFFER, 'minutes'));
releaseTime.isBetween(moment(), moment().add(LIVESTREAM_STARTS_SOON_BUFFER, 'minutes'));
const claimReleaseStartedRecently = () =>
release.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment());
releaseTime.isBetween(moment().subtract(LIVESTREAM_STARTED_RECENTLY_BUFFER, 'minutes'), moment());
const checkShowLivestream = () =>
isChannelBroadcasting &&
@ -141,7 +140,7 @@ export default function LivestreamPage(props: Props) {
}
return () => clearInterval(intervalId);
}, [chatDisabled, isChannelBroadcasting, release, isCurrentClaimLive, isInitialized]);
}, [chatDisabled, isChannelBroadcasting, releaseTime, isCurrentClaimLive, isInitialized]);
React.useEffect(() => {
if (uri && stringifiedClaim) {
@ -181,7 +180,7 @@ export default function LivestreamPage(props: Props) {
<LivestreamLayout
uri={uri}
hideComments={hideComments}
release={release}
releaseTimeMs={releaseTime.unix() * 1000}
isCurrentClaimLive={isCurrentClaimLive}
showLivestream={showLivestream}
showScheduledInfo={showScheduledInfo}

View file

@ -36,7 +36,12 @@ export function hmsToSeconds(str: string) {
// Only intended use of future dates is for claims, in case of scheduled
// publishes or livestreams, used in util/formatAriaLabel
export function getTimeAgoStr(date: any, showFutureDate?: boolean, genericSecondsString?: boolean) {
export function getTimeAgoStr(
date: any,
showFutureDate?: boolean,
genericSecondsString?: boolean,
zeroDurationStr: string = 'Just now'
) {
const suffixList = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];
let duration = 0;
let suffix = '';
@ -59,7 +64,7 @@ export function getTimeAgoStr(date: any, showFutureDate?: boolean, genericSecond
str = suffix === 'seconds' ? 'in a few seconds' : 'in %duration% ' + suffix;
duration = duration * -1;
} else if (duration <= 0) {
str = 'Just now';
str = zeroDurationStr;
} else {
str = suffix === 'seconds' && genericSecondsString ? 'A few seconds ago' : '%duration% ' + suffix + ' ago';
}