2019-10-17 05:38:09 -07:00
|
|
|
import $ from 'jquery';
|
|
|
|
import React, { Component } from 'react';
|
2021-09-03 08:41:20 -07:00
|
|
|
import { Button, Input, InputGroup, InputGroupAddon } from 'reactstrap';
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
import moment from 'moment-timezone';
|
|
|
|
|
|
|
|
import 'tempusdominus-core';
|
|
|
|
import 'tempusdominus-bootstrap-4';
|
2021-09-10 06:38:20 -07:00
|
|
|
import 'tempusdominus-bootstrap-4/build/css/tempusdominus-bootstrap-4.min.css';
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
import { dom, library } from '@fortawesome/fontawesome-svg-core';
|
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
|
|
import {
|
2021-09-03 08:41:20 -07:00
|
|
|
faArrowDown,
|
|
|
|
faArrowUp,
|
|
|
|
faCalendarCheck,
|
2019-10-17 05:38:09 -07:00
|
|
|
faChevronLeft,
|
|
|
|
faChevronRight,
|
|
|
|
faTimes,
|
|
|
|
} from '@fortawesome/free-solid-svg-icons';
|
|
|
|
|
2019-11-05 07:15:18 -08:00
|
|
|
library.add(faChevronLeft, faChevronRight, faCalendarCheck, faArrowUp, faArrowDown, faTimes);
|
2019-10-17 05:38:09 -07:00
|
|
|
// Sadly needed to also replace <i> within the date picker, since it's not a React component.
|
|
|
|
dom.watch();
|
|
|
|
|
|
|
|
interface TimeInputProps {
|
|
|
|
time: number | null; // Timestamp in milliseconds.
|
2020-01-24 14:44:18 -08:00
|
|
|
useLocalTime: boolean;
|
2019-10-17 05:38:09 -07:00
|
|
|
range: number; // Range in seconds.
|
|
|
|
placeholder: string;
|
|
|
|
onChangeTime: (time: number | null) => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
class TimeInput extends Component<TimeInputProps> {
|
|
|
|
private timeInputRef = React.createRef<HTMLInputElement>();
|
2021-09-03 08:41:20 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
2019-12-17 01:50:58 -08:00
|
|
|
private $time: any = null;
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
getBaseTime = (): number => {
|
|
|
|
return this.props.time || moment().valueOf();
|
2019-10-28 07:02:42 -07:00
|
|
|
};
|
2019-10-17 05:38:09 -07:00
|
|
|
|
2021-09-03 08:41:20 -07:00
|
|
|
calcShiftRange = (): number => this.props.range / 2;
|
2019-12-17 01:50:58 -08:00
|
|
|
|
2019-10-17 05:38:09 -07:00
|
|
|
increaseTime = (): void => {
|
2019-12-17 01:50:58 -08:00
|
|
|
const time = this.getBaseTime() + this.calcShiftRange();
|
2019-10-17 05:38:09 -07:00
|
|
|
this.props.onChangeTime(time);
|
2019-10-28 07:02:42 -07:00
|
|
|
};
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
decreaseTime = (): void => {
|
2019-12-17 01:50:58 -08:00
|
|
|
const time = this.getBaseTime() - this.calcShiftRange();
|
2019-10-17 05:38:09 -07:00
|
|
|
this.props.onChangeTime(time);
|
2019-10-28 07:02:42 -07:00
|
|
|
};
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
clearTime = (): void => {
|
|
|
|
this.props.onChangeTime(null);
|
2019-10-28 07:02:42 -07:00
|
|
|
};
|
2019-10-17 05:38:09 -07:00
|
|
|
|
2020-01-24 14:44:18 -08:00
|
|
|
timezone = (): string => {
|
|
|
|
return this.props.useLocalTime ? moment.tz.guess() : 'UTC';
|
|
|
|
};
|
|
|
|
|
2021-09-03 08:41:20 -07:00
|
|
|
componentDidMount(): void {
|
|
|
|
if (!this.timeInputRef.current) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.$time = $(this.timeInputRef.current);
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
this.$time.datetimepicker({
|
|
|
|
icons: {
|
|
|
|
today: 'fas fa-calendar-check',
|
|
|
|
},
|
|
|
|
buttons: {
|
|
|
|
//showClear: true,
|
|
|
|
showClose: true,
|
|
|
|
showToday: true,
|
|
|
|
},
|
|
|
|
sideBySide: true,
|
2019-12-17 01:50:58 -08:00
|
|
|
format: 'YYYY-MM-DD HH:mm:ss',
|
2019-10-17 05:38:09 -07:00
|
|
|
locale: 'en',
|
2020-01-24 14:44:18 -08:00
|
|
|
timeZone: this.timezone(),
|
2019-10-17 05:38:09 -07:00
|
|
|
defaultDate: this.props.time,
|
|
|
|
});
|
|
|
|
|
2021-09-03 08:41:20 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
2019-10-17 05:38:09 -07:00
|
|
|
this.$time.on('change.datetimepicker', (e: any) => {
|
2021-06-30 01:40:43 -07:00
|
|
|
// The end time can also be set by dragging a section on the graph,
|
|
|
|
// and that value will have decimal places.
|
2021-09-03 08:41:20 -07:00
|
|
|
if (e.date && e.date.valueOf() !== Math.trunc(this.props.time?.valueOf() || NaN)) {
|
2019-10-17 05:38:09 -07:00
|
|
|
this.props.onChangeTime(e.date.valueOf());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-09-03 08:41:20 -07:00
|
|
|
componentWillUnmount(): void {
|
2019-10-17 05:38:09 -07:00
|
|
|
this.$time.datetimepicker('destroy');
|
|
|
|
}
|
|
|
|
|
2021-09-03 08:41:20 -07:00
|
|
|
componentDidUpdate(prevProps: TimeInputProps): void {
|
2020-01-24 14:44:18 -08:00
|
|
|
const { time, useLocalTime } = this.props;
|
|
|
|
if (prevProps.time !== time) {
|
|
|
|
this.$time.datetimepicker('date', time ? moment(time) : null);
|
|
|
|
}
|
|
|
|
if (prevProps.useLocalTime !== useLocalTime) {
|
|
|
|
this.$time.datetimepicker('options', { timeZone: this.timezone(), defaultDate: null });
|
|
|
|
}
|
2019-10-17 05:38:09 -07:00
|
|
|
}
|
|
|
|
|
2021-09-03 08:41:20 -07:00
|
|
|
render(): JSX.Element {
|
2019-10-17 05:38:09 -07:00
|
|
|
return (
|
|
|
|
<InputGroup className="time-input" size="sm">
|
|
|
|
<InputGroupAddon addonType="prepend">
|
2019-10-28 07:02:42 -07:00
|
|
|
<Button title="Decrease time" onClick={this.decreaseTime}>
|
|
|
|
<FontAwesomeIcon icon={faChevronLeft} fixedWidth />
|
|
|
|
</Button>
|
2019-10-17 05:38:09 -07:00
|
|
|
</InputGroupAddon>
|
|
|
|
|
|
|
|
<Input
|
|
|
|
placeholder={this.props.placeholder}
|
|
|
|
innerRef={this.timeInputRef}
|
|
|
|
onFocus={() => this.$time.datetimepicker('show')}
|
|
|
|
onBlur={() => this.$time.datetimepicker('hide')}
|
2021-09-03 08:41:20 -07:00
|
|
|
onKeyDown={(e) => ['Escape', 'Enter'].includes(e.key) && this.$time.datetimepicker('hide')}
|
2019-10-17 05:38:09 -07:00
|
|
|
/>
|
|
|
|
|
|
|
|
{/* CAUTION: While the datetimepicker also has an option to show a 'clear' button,
|
|
|
|
that functionality is broken, so we create an external solution instead. */}
|
2019-10-28 07:02:42 -07:00
|
|
|
{this.props.time && (
|
2019-10-17 05:38:09 -07:00
|
|
|
<InputGroupAddon addonType="append">
|
2021-04-15 09:14:07 -07:00
|
|
|
<Button outline className="clear-time-btn" title="Clear time" onClick={this.clearTime}>
|
2019-10-28 07:02:42 -07:00
|
|
|
<FontAwesomeIcon icon={faTimes} fixedWidth />
|
|
|
|
</Button>
|
2019-10-17 05:38:09 -07:00
|
|
|
</InputGroupAddon>
|
2019-10-28 07:02:42 -07:00
|
|
|
)}
|
2019-10-17 05:38:09 -07:00
|
|
|
|
|
|
|
<InputGroupAddon addonType="append">
|
2019-10-28 07:02:42 -07:00
|
|
|
<Button title="Increase time" onClick={this.increaseTime}>
|
|
|
|
<FontAwesomeIcon icon={faChevronRight} fixedWidth />
|
|
|
|
</Button>
|
2019-10-17 05:38:09 -07:00
|
|
|
</InputGroupAddon>
|
|
|
|
</InputGroup>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default TimeInput;
|