2019-11-06 12:12:41 +00:00
|
|
|
import React from "react";
|
|
|
|
|
import BaseControl, { ControlProps } from "./BaseControl";
|
2020-04-23 06:12:13 +00:00
|
|
|
import { StyledDatePicker } from "./StyledControls";
|
2019-11-06 12:12:41 +00:00
|
|
|
import moment from "moment-timezone";
|
2020-04-15 11:42:11 +00:00
|
|
|
import styled from "styled-components";
|
|
|
|
|
import { TimePrecision } from "@blueprintjs/datetime";
|
2020-06-25 10:04:57 +00:00
|
|
|
import { WidgetProps } from "widgets/BaseWidget";
|
2020-11-27 08:48:38 +00:00
|
|
|
import { Toaster } from "components/ads/Toast";
|
|
|
|
|
import { Variant } from "components/ads/common";
|
2021-02-02 14:42:49 +00:00
|
|
|
import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
|
2020-04-15 11:42:11 +00:00
|
|
|
|
2020-11-27 08:48:38 +00:00
|
|
|
const DatePickerControlWrapper = styled.div<{ isValid: boolean }>`
|
2020-04-15 11:42:11 +00:00
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
2020-04-29 10:29:02 +00:00
|
|
|
margin: 8px 0 0 0;
|
2020-04-15 11:42:11 +00:00
|
|
|
&&& {
|
|
|
|
|
input {
|
2020-12-24 04:32:25 +00:00
|
|
|
background: ${(props) => props.theme.colors.paneTextBG};
|
|
|
|
|
color: ${(props) => props.theme.colors.textOnDarkBG};
|
|
|
|
|
font-size: ${(props) => props.theme.fontSizes[3]}px;
|
2020-04-15 11:42:11 +00:00
|
|
|
box-shadow: none;
|
2020-12-24 04:32:25 +00:00
|
|
|
border: ${(props) =>
|
2020-11-27 08:48:38 +00:00
|
|
|
!props.isValid
|
|
|
|
|
? `1px solid ${props.theme.colors.error}`
|
|
|
|
|
: `1px solid transparent`};
|
2020-04-15 11:42:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-04-29 10:29:02 +00:00
|
|
|
.vertical-center {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin: 16px 0 4px 0;
|
|
|
|
|
.label {
|
2020-12-24 04:32:25 +00:00
|
|
|
color: ${(props) => props.theme.colors.paneText};
|
|
|
|
|
font-size: ${(props) => props.theme.fontSizes[3]}px;
|
2020-04-29 10:29:02 +00:00
|
|
|
}
|
|
|
|
|
.bp3-control {
|
|
|
|
|
margin-bottom: 0px;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-15 11:42:11 +00:00
|
|
|
`;
|
|
|
|
|
|
2020-05-07 10:51:37 +00:00
|
|
|
class DatePickerControl extends BaseControl<
|
|
|
|
|
DatePickerControlProps,
|
|
|
|
|
DatePickerControlState
|
|
|
|
|
> {
|
2020-06-19 07:51:07 +00:00
|
|
|
now = moment();
|
|
|
|
|
year = this.now.get("year");
|
|
|
|
|
maxDate: Date = this.now
|
|
|
|
|
.clone()
|
|
|
|
|
.set({ month: 11, date: 31, year: this.year + 20 })
|
|
|
|
|
.toDate();
|
|
|
|
|
minDate: Date = this.now
|
|
|
|
|
.clone()
|
|
|
|
|
.set({ month: 0, date: 1, year: this.year - 20 })
|
|
|
|
|
.toDate();
|
|
|
|
|
|
2020-05-07 10:51:37 +00:00
|
|
|
constructor(props: DatePickerControlProps) {
|
|
|
|
|
super(props);
|
|
|
|
|
this.state = {
|
|
|
|
|
selectedDate: props.propertyValue,
|
|
|
|
|
};
|
|
|
|
|
}
|
2020-06-19 07:51:07 +00:00
|
|
|
|
2019-11-06 12:12:41 +00:00
|
|
|
render() {
|
2021-02-02 14:42:49 +00:00
|
|
|
const dateFormat =
|
|
|
|
|
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
|
|
|
|
const isValid = this.state.selectedDate
|
|
|
|
|
? this.validateDate(moment(this.state.selectedDate, dateFormat).toDate())
|
|
|
|
|
: true;
|
|
|
|
|
const maxDate =
|
|
|
|
|
this.props.widgetProperties?.evaluatedValues?.maxDate ?? this.maxDate;
|
|
|
|
|
const minDate =
|
|
|
|
|
this.props.widgetProperties?.evaluatedValues?.minDate ?? this.minDate;
|
2021-02-03 11:30:19 +00:00
|
|
|
|
2019-11-06 12:12:41 +00:00
|
|
|
return (
|
2021-02-02 14:42:49 +00:00
|
|
|
<DatePickerControlWrapper isValid={isValid}>
|
2020-04-15 11:42:11 +00:00
|
|
|
<StyledDatePicker
|
|
|
|
|
formatDate={this.formatDate}
|
|
|
|
|
parseDate={this.parseDate}
|
2020-04-23 06:12:13 +00:00
|
|
|
placeholder="DD/MM/YYYY HH:mm"
|
2020-04-15 11:42:11 +00:00
|
|
|
showActionsBar
|
2020-04-23 06:12:13 +00:00
|
|
|
timePrecision={TimePrecision.MINUTE}
|
2020-04-15 11:42:11 +00:00
|
|
|
closeOnSelection
|
|
|
|
|
onChange={this.onDateSelected}
|
2021-02-02 14:42:49 +00:00
|
|
|
maxDate={
|
|
|
|
|
this.props.propertyName === "defaultDate"
|
2021-02-03 11:30:19 +00:00
|
|
|
? this.getValidDate(maxDate, dateFormat)
|
2021-02-02 14:42:49 +00:00
|
|
|
: undefined
|
|
|
|
|
}
|
|
|
|
|
minDate={
|
|
|
|
|
this.props.propertyName === "defaultDate"
|
2021-02-03 11:30:19 +00:00
|
|
|
? this.getValidDate(minDate, dateFormat)
|
2021-02-02 14:42:49 +00:00
|
|
|
: undefined
|
|
|
|
|
}
|
2020-04-29 10:29:02 +00:00
|
|
|
value={
|
2021-02-03 11:30:19 +00:00
|
|
|
this.props.propertyValue && isValid
|
2020-06-19 07:51:07 +00:00
|
|
|
? this.parseDate(this.props.propertyValue)
|
2020-04-29 10:29:02 +00:00
|
|
|
: null
|
|
|
|
|
}
|
2020-04-15 11:42:11 +00:00
|
|
|
/>
|
|
|
|
|
</DatePickerControlWrapper>
|
2019-11-06 12:12:41 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-03 11:30:19 +00:00
|
|
|
getValidDate = (date: string, format: string) => {
|
|
|
|
|
const _date = moment(date, format);
|
|
|
|
|
return _date.isValid() ? _date.toDate() : undefined;
|
|
|
|
|
};
|
|
|
|
|
|
2020-11-27 08:48:38 +00:00
|
|
|
/**
|
|
|
|
|
* here we put the selected state into state
|
|
|
|
|
* before putting it into state, we check if widget date is in range
|
|
|
|
|
* of property value ( min /max range )
|
|
|
|
|
*
|
|
|
|
|
* @param date
|
|
|
|
|
*/
|
2021-02-02 14:42:49 +00:00
|
|
|
onDateSelected = (date: Date, isUserChange: boolean): void => {
|
|
|
|
|
if (isUserChange) {
|
|
|
|
|
const selectedDate = date ? this.formatDate(date) : undefined;
|
|
|
|
|
const isValid = this.validateDate(date);
|
|
|
|
|
if (!isValid) return;
|
2020-11-27 08:48:38 +00:00
|
|
|
|
2021-02-02 14:42:49 +00:00
|
|
|
// if everything is ok, put date in state
|
|
|
|
|
this.setState({ selectedDate: selectedDate });
|
|
|
|
|
this.updateProperty(this.props.propertyName, selectedDate);
|
|
|
|
|
}
|
2020-04-15 11:42:11 +00:00
|
|
|
};
|
|
|
|
|
|
2020-11-27 08:48:38 +00:00
|
|
|
/**
|
|
|
|
|
* checks:
|
|
|
|
|
* 1. if max date is greater than the default date
|
|
|
|
|
* 2. if default date is in range of min and max date
|
|
|
|
|
*/
|
|
|
|
|
validateDate = (date: Date): boolean => {
|
2021-02-02 14:42:49 +00:00
|
|
|
const dateFormat =
|
|
|
|
|
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
|
|
|
|
const parsedSelectedDate = moment(date, dateFormat);
|
|
|
|
|
//validate defaultDate if both minDate and maxDate is already selected
|
|
|
|
|
if (this.props.propertyName === "defaultDate") {
|
|
|
|
|
if (
|
|
|
|
|
parsedSelectedDate.isValid() &&
|
|
|
|
|
this.props.widgetProperties?.evaluatedValues?.minDate &&
|
|
|
|
|
this.props.widgetProperties?.evaluatedValues?.maxDate
|
|
|
|
|
) {
|
|
|
|
|
const parsedMinDate = moment(
|
|
|
|
|
this.props.widgetProperties.evaluatedValues.minDate,
|
|
|
|
|
dateFormat,
|
|
|
|
|
);
|
|
|
|
|
const parsedMaxDate = moment(
|
|
|
|
|
this.props.widgetProperties.evaluatedValues.maxDate,
|
|
|
|
|
dateFormat,
|
|
|
|
|
);
|
|
|
|
|
if (
|
|
|
|
|
parsedSelectedDate.isBefore(parsedMinDate) ||
|
|
|
|
|
parsedSelectedDate.isAfter(parsedMaxDate)
|
|
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-27 08:48:38 +00:00
|
|
|
if (this.props.widgetProperties?.evaluatedValues?.value) {
|
|
|
|
|
const parsedWidgetDate = moment(
|
|
|
|
|
this.props.widgetProperties.evaluatedValues.value,
|
2021-02-02 14:42:49 +00:00
|
|
|
dateFormat,
|
2020-11-27 08:48:38 +00:00
|
|
|
);
|
|
|
|
|
// checking if widget date is after min date
|
|
|
|
|
if (this.props.propertyName === "minDate") {
|
|
|
|
|
if (
|
|
|
|
|
parsedSelectedDate.isValid() &&
|
|
|
|
|
parsedWidgetDate.isBefore(parsedSelectedDate)
|
|
|
|
|
) {
|
|
|
|
|
Toaster.show({
|
|
|
|
|
text: "Min date cannot be greater than current widget value.",
|
|
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checking if widget date is before max date
|
|
|
|
|
if (this.props.propertyName === "maxDate") {
|
|
|
|
|
if (
|
|
|
|
|
parsedSelectedDate.isValid() &&
|
|
|
|
|
parsedWidgetDate.isAfter(parsedSelectedDate)
|
|
|
|
|
) {
|
|
|
|
|
Toaster.show({
|
|
|
|
|
text: "Max date cannot be less than current widget value.",
|
|
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-15 11:42:11 +00:00
|
|
|
formatDate = (date: Date): string => {
|
2021-02-02 14:42:49 +00:00
|
|
|
const dateFormat =
|
|
|
|
|
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
|
|
|
|
return moment(date).format(dateFormat);
|
2020-04-15 11:42:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
parseDate = (dateStr: string): Date => {
|
2021-02-02 14:42:49 +00:00
|
|
|
const dateFormat =
|
|
|
|
|
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
2021-02-03 11:30:19 +00:00
|
|
|
const date = moment(dateStr, dateFormat);
|
|
|
|
|
|
|
|
|
|
if (date.isValid()) return moment(dateStr, dateFormat).toDate();
|
|
|
|
|
else return moment().toDate();
|
2019-11-06 12:12:41 +00:00
|
|
|
};
|
|
|
|
|
|
2020-04-14 05:35:16 +00:00
|
|
|
static getControlType() {
|
2019-11-06 12:12:41 +00:00
|
|
|
return "DATE_PICKER";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface DatePickerControlProps extends ControlProps {
|
|
|
|
|
placeholderText: string;
|
2020-04-23 06:12:13 +00:00
|
|
|
propertyValue: string;
|
2020-06-19 07:51:07 +00:00
|
|
|
widgetProperties: WidgetProps;
|
2019-11-06 12:12:41 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-07 10:51:37 +00:00
|
|
|
interface DatePickerControlState {
|
2020-06-09 13:04:47 +00:00
|
|
|
selectedDate?: string;
|
2020-05-07 10:51:37 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 12:12:41 +00:00
|
|
|
export default DatePickerControl;
|