204 lines
4.4 KiB
React
204 lines
4.4 KiB
React
|
import React, { Component } from 'react';
|
||
|
import Icon from '/imports/ui/components/common/icon/component';
|
||
|
import TimerService from '/imports/ui/components/timer/service';
|
||
|
import Styled from './styles';
|
||
|
|
||
|
const CDN = Meteor.settings.public.app.cdn;
|
||
|
const BASENAME = Meteor.settings.public.app.basename;
|
||
|
const HOST = CDN + BASENAME;
|
||
|
|
||
|
class Indicator extends Component {
|
||
|
constructor(props) {
|
||
|
super(props);
|
||
|
|
||
|
this.timeRef = React.createRef();
|
||
|
this.interval = null;
|
||
|
|
||
|
this.alarm = null;
|
||
|
// We need to avoid trigger on mount
|
||
|
this.triggered = true;
|
||
|
|
||
|
this.updateTime = this.updateTime.bind(this);
|
||
|
}
|
||
|
|
||
|
componentDidMount() {
|
||
|
const { timer } = this.props;
|
||
|
const { running } = timer;
|
||
|
|
||
|
this.alarm = new Audio(`${HOST}/resources/sounds/alarm.mp3`);
|
||
|
this.triggered = this.initTriggered();
|
||
|
|
||
|
const { current } = this.timeRef;
|
||
|
if (current && running) {
|
||
|
this.interval = setInterval(this.updateTime, TimerService.getInterval());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
componentDidUpdate(prevProps) {
|
||
|
const { timer } = this.props;
|
||
|
const { timer: prevTimer } = prevProps;
|
||
|
|
||
|
this.updateInterval(prevTimer, timer);
|
||
|
this.updateAlarmTrigger(prevTimer, timer);
|
||
|
}
|
||
|
|
||
|
componentWillUnmount() {
|
||
|
clearInterval(this.interval);
|
||
|
}
|
||
|
|
||
|
updateInterval(prevTimer, timer) {
|
||
|
const { running } = timer;
|
||
|
const { running: prevRunning } = prevTimer;
|
||
|
|
||
|
if (!prevRunning && running) {
|
||
|
this.interval = setInterval(this.updateTime, TimerService.getInterval());
|
||
|
}
|
||
|
|
||
|
if (prevRunning && !running) {
|
||
|
clearInterval(this.interval);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
updateAlarmTrigger(prevTimer, timer) {
|
||
|
const {
|
||
|
accumulated,
|
||
|
timestamp,
|
||
|
} = timer;
|
||
|
|
||
|
const { timestamp: prevTimestamp } = prevTimer;
|
||
|
|
||
|
const reseted = timestamp !== prevTimestamp && accumulated === 0;
|
||
|
|
||
|
if (reseted) {
|
||
|
this.triggered = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
initTriggered() {
|
||
|
const {
|
||
|
timer,
|
||
|
timeOffset,
|
||
|
} = this.props;
|
||
|
|
||
|
const {
|
||
|
stopwatch,
|
||
|
running,
|
||
|
} = timer;
|
||
|
|
||
|
if (stopwatch || !running) return false;
|
||
|
|
||
|
const {
|
||
|
time,
|
||
|
accumulated,
|
||
|
timestamp,
|
||
|
} = timer;
|
||
|
|
||
|
const elapsedTime = TimerService.getElapsedTime(running, timestamp, timeOffset, accumulated);
|
||
|
const updatedTime = Math.max(time - elapsedTime, 0);
|
||
|
|
||
|
if (updatedTime === 0) return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
play() {
|
||
|
if (this.alarm && !this.triggered) {
|
||
|
this.triggered = true;
|
||
|
this.alarm.play();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
soundAlarm(time) {
|
||
|
const { timer } = this.props;
|
||
|
const {
|
||
|
running,
|
||
|
stopwatch,
|
||
|
} = timer;
|
||
|
|
||
|
const enabled = TimerService.isAlarmEnabled();
|
||
|
const zero = time === 0;
|
||
|
|
||
|
return enabled && running && zero && !stopwatch;
|
||
|
}
|
||
|
|
||
|
getTime() {
|
||
|
const {
|
||
|
timer,
|
||
|
timeOffset,
|
||
|
} = this.props;
|
||
|
|
||
|
const {
|
||
|
stopwatch,
|
||
|
running,
|
||
|
time,
|
||
|
accumulated,
|
||
|
timestamp,
|
||
|
} = timer;
|
||
|
|
||
|
const elapsedTime = TimerService.getElapsedTime(running, timestamp, timeOffset, accumulated);
|
||
|
|
||
|
let updatedTime;
|
||
|
if (stopwatch) {
|
||
|
updatedTime = elapsedTime;
|
||
|
} else {
|
||
|
updatedTime = Math.max(time - elapsedTime, 0);
|
||
|
}
|
||
|
|
||
|
if (this.soundAlarm(updatedTime)) {
|
||
|
this.play();
|
||
|
}
|
||
|
|
||
|
return TimerService.getTimeAsString(updatedTime, stopwatch);
|
||
|
}
|
||
|
|
||
|
updateTime() {
|
||
|
const { current } = this.timeRef;
|
||
|
if (current) {
|
||
|
current.textContent = this.getTime();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
render() {
|
||
|
const { isTimerActive } = this.props;
|
||
|
if (!isTimerActive) return null;
|
||
|
|
||
|
const {
|
||
|
isModerator,
|
||
|
hidden,
|
||
|
timer,
|
||
|
} = this.props;
|
||
|
const { running } = timer;
|
||
|
|
||
|
const onClick = running ? TimerService.stopTimer : TimerService.startTimer;
|
||
|
|
||
|
return (
|
||
|
<Styled.TimerWrapper>
|
||
|
<Styled.Timer>
|
||
|
<Styled.TimerIndicator
|
||
|
role="button"
|
||
|
tabIndex={0}
|
||
|
running={running}
|
||
|
disabled={!isModerator}
|
||
|
hide={hidden}
|
||
|
onClick={isModerator ? onClick : null}
|
||
|
>
|
||
|
<Styled.TimerContent>
|
||
|
<Styled.TimerIcon>
|
||
|
<Icon iconName="time" />
|
||
|
</Styled.TimerIcon>
|
||
|
<Styled.TimerTime
|
||
|
aria-hidden
|
||
|
ref={this.timeRef}
|
||
|
>
|
||
|
{this.getTime()}
|
||
|
</Styled.TimerTime>
|
||
|
</Styled.TimerContent>
|
||
|
</Styled.TimerIndicator>
|
||
|
</Styled.Timer>
|
||
|
</Styled.TimerWrapper>
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export default Indicator;
|