Files
karma/ui/src/Components/SilenceModal/DateTimeSelect/index.js
Łukasz Mierzwa 44e4d90651 chore(ui): react-datepicker 2.0 uses Date instead of moment
Latest react-datepicker no longer accepts moment instances, it uses plain js Date objects instead.
Migrate code to pass props as Date.
2018-11-19 21:40:05 +00:00

278 lines
8.2 KiB
JavaScript

import React, { Component } from "react";
import PropTypes from "prop-types";
import { observable, action } from "mobx";
import { observer } from "mobx-react";
import moment from "moment";
import DatePicker from "react-datepicker";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { Duration } from "./Duration";
import { HourMinute } from "./HourMinute";
import "./index.scss";
const OffsetBadge = ({ startDate, endDate, prefixLabel }) => {
const days = endDate.diff(startDate, "days");
const hours = endDate.diff(startDate, "hours") % 24;
const minutes = endDate.diff(startDate, "minutes") % 60;
return (
<span className="badge badge-light">
{days <= 0 && hours <= 0 && minutes <= 0 ? "now" : prefixLabel}
{days > 0 ? `${days}d ` : null}
{hours > 0 ? `${hours}h ` : null}
{minutes > 0 ? `${minutes}m ` : null}
</span>
);
};
OffsetBadge.propTypes = {
startDate: PropTypes.instanceOf(moment).isRequired,
endDate: PropTypes.instanceOf(moment).isRequired,
prefixLabel: PropTypes.string.isRequired
};
const Tab = ({ title, active, onClick }) => (
<li className="nav-item">
<span
className={`nav-link cursor-pointer ${active ? "active" : ""}`}
onClick={onClick}
>
{title}
</span>
</li>
);
Tab.propTypes = {
title: PropTypes.node.isRequired,
active: PropTypes.bool,
onClick: PropTypes.func.isRequired
};
const TabNames = Object.freeze({
Start: "start",
End: "end",
Duration: "duration"
});
const TabContentStart = observer(({ silenceFormStore }) => {
return (
<div className="d-flex flex-sm-row flex-column justify-content-around mx-3 mt-2 ">
<DatePicker
inline
todayButton={"Today"}
minDate={moment()
.second(0)
.toDate()}
selected={silenceFormStore.data.startsAt.toDate()}
onChange={val => {
silenceFormStore.data.startsAt = moment(val);
silenceFormStore.data.verifyStarEnd();
}}
/>
<HourMinute
dateValue={silenceFormStore.data.startsAt}
onHourInc={() => silenceFormStore.data.incStart(60)}
onHourDec={() => silenceFormStore.data.decStart(60)}
onMinuteInc={() => silenceFormStore.data.incStart(1)}
onMinuteDec={() => silenceFormStore.data.decStart(1)}
/>
</div>
);
});
const TabContentEnd = observer(({ silenceFormStore }) => {
return (
<div className="d-flex flex-sm-row flex-column justify-content-around mx-3 mt-2 ">
<DatePicker
inline
todayButton={"Today"}
minDate={moment()
.second(0)
.add(1, "minutes")
.toDate()}
selected={silenceFormStore.data.endsAt.toDate()}
onChange={val => {
silenceFormStore.data.endsAt = moment(val);
silenceFormStore.data.verifyStarEnd();
}}
/>
<HourMinute
dateValue={silenceFormStore.data.endsAt}
onHourInc={() => silenceFormStore.data.incEnd(60)}
onHourDec={() => silenceFormStore.data.decEnd(60)}
onMinuteInc={() => silenceFormStore.data.incEnd(1)}
onMinuteDec={() => silenceFormStore.data.decEnd(1)}
/>
</div>
);
});
// calculate value for duration increase button using a goal step
const CalculateChangeValueUp = (currentValue, step) => {
// if current value is less than step (but >0) then use 1
if (currentValue > 0 && currentValue < step) {
return 1;
}
// otherwise use step or a value that moves current value to the next step
return step - (currentValue % step);
};
// calculate value for duration decrease button using a goal step
const CalculateChangeValueDown = (currentValue, step) => {
// if current value is less than step (but >0) then use 1
if (currentValue > 0 && currentValue < step) {
return 1;
}
// otherwise use step or a value that moves current value to the next step
return currentValue % step || step;
};
const TabContentDuration = observer(({ silenceFormStore }) => {
return (
<div className="d-flex flex-sm-row flex-column justify-content-around mt-2 mx-3">
<Duration
label="days"
value={silenceFormStore.data.toDuration.days}
onInc={() => silenceFormStore.data.incEnd(60 * 24)}
onDec={() => silenceFormStore.data.decEnd(60 * 24)}
/>
<Duration
label="hours"
value={silenceFormStore.data.toDuration.hours}
onInc={() => silenceFormStore.data.incEnd(60)}
onDec={() => silenceFormStore.data.decEnd(60)}
/>
<Duration
label="minutes"
value={silenceFormStore.data.toDuration.minutes}
onInc={() =>
silenceFormStore.data.incEnd(
CalculateChangeValueUp(silenceFormStore.data.toDuration.minutes, 5)
)
}
onDec={() =>
silenceFormStore.data.decEnd(
CalculateChangeValueDown(
silenceFormStore.data.toDuration.minutes,
5
)
)
}
/>
</div>
);
});
TabContentDuration.propTypes = {
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired
};
const DateTimeSelect = observer(
class DateTimeSelect extends Component {
static propTypes = {
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired
};
tab = observable(
{
current: TabNames.Duration,
setStart() {
this.current = TabNames.Start;
},
setEnd() {
this.current = TabNames.End;
},
setDuration() {
this.current = TabNames.Duration;
},
timeNow: moment().seconds(0),
updateTimeNow() {
this.timeNow = moment().seconds(0);
}
},
{
setStart: action.bound,
setEnd: action.bound,
setDuration: action.bound,
updateTimeNow: action.bound
}
);
componentDidMount() {
this.tab.updateTimeNow();
this.nowUpdateTimer = setInterval(this.tab.updateTimeNow, 30 * 1000);
}
componentWillUnmount() {
clearInterval(this.nowUpdateTimer);
this.nowUpdateTimer = null;
}
render() {
const { silenceFormStore } = this.props;
return (
<React.Fragment>
<ul className="nav nav-tabs nav-fill">
<Tab
title={
<React.Fragment>
<span className="mr-1">Starts</span>
<OffsetBadge
prefixLabel="in "
startDate={this.tab.timeNow}
endDate={silenceFormStore.data.startsAt}
/>
</React.Fragment>
}
active={this.tab.current === TabNames.Start}
onClick={this.tab.setStart}
/>
<Tab
title={
<React.Fragment>
<span className="mr-1">Ends</span>
<OffsetBadge
prefixLabel="in "
startDate={this.tab.timeNow}
endDate={silenceFormStore.data.endsAt}
/>
</React.Fragment>
}
active={this.tab.current === TabNames.End}
onClick={this.tab.setEnd}
/>
<Tab
title={
<React.Fragment>
<span className="mr-1">Duration</span>
<OffsetBadge
prefixLabel=""
startDate={silenceFormStore.data.startsAt}
endDate={silenceFormStore.data.endsAt}
/>
</React.Fragment>
}
active={this.tab.current === TabNames.Duration}
onClick={this.tab.setDuration}
/>
</ul>
<div className="tab-content mb-3">
{this.tab.current === TabNames.Duration ? (
<TabContentDuration silenceFormStore={silenceFormStore} />
) : null}
{this.tab.current === TabNames.Start ? (
<TabContentStart silenceFormStore={silenceFormStore} />
) : null}
{this.tab.current === TabNames.End ? (
<TabContentEnd silenceFormStore={silenceFormStore} />
) : null}
</div>
</React.Fragment>
);
}
}
);
export { DateTimeSelect, TabContentStart, TabContentEnd, TabContentDuration };