Date picker validation fixed (#2789)
* Date picker validation fixed * Added date value check to remove unncessary validations Commented defaultDate validation test as invalid date cannot be saved in date control * Fixed date selection on user change Fixed min and max date parsing for date picker control default date * Added validation for min and max date in validations to handle validations when field is converted to JS
This commit is contained in:
parent
9d97645b3c
commit
11f5687b38
|
|
@ -101,18 +101,18 @@ describe("DatePicker Widget Functionality", function() {
|
|||
);
|
||||
});
|
||||
|
||||
it("Datepicker default date validation", function() {
|
||||
cy.get(formWidgetsPage.defaultDate).click();
|
||||
cy.wait(1000);
|
||||
cy.setDate(-2, "ddd MMM DD YYYY");
|
||||
cy.get(formWidgetsPage.defaultDate).should(
|
||||
"have.css",
|
||||
"border",
|
||||
"1px solid rgb(206, 66, 87)",
|
||||
);
|
||||
// it("Datepicker default date validation", function() {
|
||||
// cy.get(formWidgetsPage.defaultDate).click();
|
||||
// cy.wait(1000);
|
||||
// cy.setDate(-2, "ddd MMM DD YYYY");
|
||||
// cy.get(formWidgetsPage.defaultDate).should(
|
||||
// "have.css",
|
||||
// "border",
|
||||
// "1px solid rgb(206, 66, 87)",
|
||||
// );
|
||||
|
||||
cy.PublishtheApp();
|
||||
});
|
||||
// cy.PublishtheApp();
|
||||
// });
|
||||
|
||||
// it("DatePicker-check Required field validation", function() {
|
||||
// // Check the required checkbox
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { DatePickerType } from "widgets/DatePickerWidget";
|
|||
import { WIDGET_PADDING } from "constants/WidgetConstants";
|
||||
import { TimePrecision } from "@blueprintjs/datetime";
|
||||
import { Colors } from "constants/Colors";
|
||||
import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
|
||||
|
||||
const StyledControlGroup = styled(ControlGroup)`
|
||||
&&& {
|
||||
|
|
@ -67,10 +68,11 @@ class DatePickerComponent extends React.Component<
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps: DatePickerComponentProps) {
|
||||
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
|
||||
if (
|
||||
this.props.selectedDate !== this.state.selectedDate &&
|
||||
!moment(this.props.selectedDate, this.props.dateFormat).isSame(
|
||||
moment(prevProps.selectedDate, this.props.dateFormat),
|
||||
!moment(this.props.selectedDate, dateFormat).isSame(
|
||||
moment(prevProps.selectedDate, dateFormat),
|
||||
"seconds",
|
||||
)
|
||||
) {
|
||||
|
|
@ -81,13 +83,13 @@ class DatePickerComponent extends React.Component<
|
|||
render() {
|
||||
const now = moment();
|
||||
const year = now.get("year");
|
||||
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
|
||||
const minDate = this.props.minDate
|
||||
? moment(this.props.minDate)
|
||||
? moment(this.props.minDate, dateFormat)
|
||||
: now.clone().set({ month: 0, date: 1, year: year - 100 });
|
||||
const maxDate = this.props.maxDate
|
||||
? moment(this.props.maxDate)
|
||||
? moment(this.props.maxDate, dateFormat)
|
||||
: now.clone().set({ month: 11, date: 31, year: year + 20 });
|
||||
|
||||
return (
|
||||
<StyledControlGroup
|
||||
fill
|
||||
|
|
@ -142,11 +144,13 @@ class DatePickerComponent extends React.Component<
|
|||
}
|
||||
|
||||
formatDate = (date: Date): string => {
|
||||
return moment(date).format(this.props.dateFormat);
|
||||
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
|
||||
return moment(date).format(dateFormat);
|
||||
};
|
||||
|
||||
parseDate = (dateStr: string): Date => {
|
||||
return moment(dateStr, this.props.dateFormat).toDate();
|
||||
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
|
||||
return moment(dateStr, dateFormat).toDate();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -156,16 +160,18 @@ class DatePickerComponent extends React.Component<
|
|||
*
|
||||
* @param selectedDate
|
||||
*/
|
||||
onDateSelected = (selectedDate: Date) => {
|
||||
const { onDateSelected } = this.props;
|
||||
onDateSelected = (selectedDate: Date, isUserChange: boolean) => {
|
||||
if (isUserChange) {
|
||||
const { onDateSelected } = this.props;
|
||||
|
||||
const date = selectedDate ? this.formatDate(selectedDate) : "";
|
||||
this.setState({ selectedDate: date });
|
||||
const date = selectedDate ? this.formatDate(selectedDate) : "";
|
||||
this.setState({ selectedDate: date });
|
||||
|
||||
// if date is null ( if date is cleared ), don't call onDateSelected
|
||||
if (!selectedDate) return false;
|
||||
// if date is null ( if date is cleared ), don't call onDateSelected
|
||||
if (!selectedDate) return false;
|
||||
|
||||
onDateSelected(date);
|
||||
onDateSelected(date);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { TimePrecision } from "@blueprintjs/datetime";
|
|||
import { WidgetProps } from "widgets/BaseWidget";
|
||||
import { Toaster } from "components/ads/Toast";
|
||||
import { Variant } from "components/ads/common";
|
||||
import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
|
||||
|
||||
const DatePickerControlWrapper = styled.div<{ isValid: boolean }>`
|
||||
display: flex;
|
||||
|
|
@ -62,8 +63,17 @@ class DatePickerControl extends BaseControl<
|
|||
}
|
||||
|
||||
render() {
|
||||
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;
|
||||
return (
|
||||
<DatePickerControlWrapper isValid={this.props.isValid}>
|
||||
<DatePickerControlWrapper isValid={isValid}>
|
||||
<StyledDatePicker
|
||||
formatDate={this.formatDate}
|
||||
parseDate={this.parseDate}
|
||||
|
|
@ -72,8 +82,16 @@ class DatePickerControl extends BaseControl<
|
|||
timePrecision={TimePrecision.MINUTE}
|
||||
closeOnSelection
|
||||
onChange={this.onDateSelected}
|
||||
maxDate={this.maxDate}
|
||||
minDate={this.minDate}
|
||||
maxDate={
|
||||
this.props.propertyName === "defaultDate"
|
||||
? moment(maxDate, dateFormat).toDate()
|
||||
: undefined
|
||||
}
|
||||
minDate={
|
||||
this.props.propertyName === "defaultDate"
|
||||
? moment(minDate, dateFormat).toDate()
|
||||
: undefined
|
||||
}
|
||||
value={
|
||||
this.props.propertyValue
|
||||
? this.parseDate(this.props.propertyValue)
|
||||
|
|
@ -91,15 +109,17 @@ class DatePickerControl extends BaseControl<
|
|||
*
|
||||
* @param date
|
||||
*/
|
||||
onDateSelected = (date: Date): void => {
|
||||
const selectedDate = date ? this.formatDate(date) : undefined;
|
||||
const isValid = this.validateDate(date);
|
||||
onDateSelected = (date: Date, isUserChange: boolean): void => {
|
||||
if (isUserChange) {
|
||||
const selectedDate = date ? this.formatDate(date) : undefined;
|
||||
const isValid = this.validateDate(date);
|
||||
|
||||
if (!isValid) return;
|
||||
if (!isValid) return;
|
||||
|
||||
// if everything is ok, put date in state
|
||||
this.setState({ selectedDate: selectedDate });
|
||||
this.updateProperty(this.props.propertyName, selectedDate);
|
||||
// if everything is ok, put date in state
|
||||
this.setState({ selectedDate: selectedDate });
|
||||
this.updateProperty(this.props.propertyName, selectedDate);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -108,17 +128,37 @@ class DatePickerControl extends BaseControl<
|
|||
* 2. if default date is in range of min and max date
|
||||
*/
|
||||
validateDate = (date: Date): boolean => {
|
||||
const parsedSelectedDate = moment(
|
||||
date,
|
||||
this.props.widgetProperties.dateFormat,
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.props.widgetProperties?.evaluatedValues?.value) {
|
||||
const parsedWidgetDate = moment(
|
||||
this.props.widgetProperties.evaluatedValues.value,
|
||||
this.props.widgetProperties.dateFormat,
|
||||
dateFormat,
|
||||
);
|
||||
|
||||
// checking if widget date is after min date
|
||||
if (this.props.propertyName === "minDate") {
|
||||
if (
|
||||
|
|
@ -149,21 +189,19 @@ class DatePickerControl extends BaseControl<
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
formatDate = (date: Date): string => {
|
||||
return moment(date).format(
|
||||
this.props.widgetProperties.dateFormat || "DD/MM/YYYY HH:mm",
|
||||
);
|
||||
const dateFormat =
|
||||
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
||||
return moment(date).format(dateFormat);
|
||||
};
|
||||
|
||||
parseDate = (dateStr: string): Date => {
|
||||
return moment(
|
||||
dateStr,
|
||||
this.props.widgetProperties.dateFormat || "DD/MM/YYYY HH:mm",
|
||||
).toDate();
|
||||
const dateFormat =
|
||||
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
||||
return moment(dateStr, dateFormat).toDate();
|
||||
};
|
||||
|
||||
static getControlType() {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const FIELD_VALUES: Record<
|
|||
isVisible: "boolean",
|
||||
},
|
||||
DATE_PICKER_WIDGET: {
|
||||
defaultDate: "Date",
|
||||
defaultDate: "string", //TODO:Vicky validate this property
|
||||
isRequired: "boolean",
|
||||
isVisible: "boolean",
|
||||
isDisabled: "boolean",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ export const VALIDATION_TYPES = {
|
|||
OPTIONS_DATA: "OPTIONS_DATA",
|
||||
DATE: "DATE",
|
||||
DEFAULT_DATE: "DEFAULT_DATE",
|
||||
MIN_DATE: "MIN_DATE",
|
||||
MAX_DATE: "MAX_DATE",
|
||||
TABS_DATA: "TABS_DATA",
|
||||
CHART_DATA: "CHART_DATA",
|
||||
MARKERS: "MARKERS",
|
||||
|
|
@ -39,7 +41,7 @@ export type Validator = (
|
|||
dataTree?: DataTree,
|
||||
) => ValidationResponse;
|
||||
|
||||
export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.SSSZ";
|
||||
export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.Z";
|
||||
|
||||
export const JAVASCRIPT_KEYWORDS = {
|
||||
true: "true",
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
|
|||
dateFormat: VALIDATION_TYPES.TEXT,
|
||||
label: VALIDATION_TYPES.TEXT,
|
||||
datePickerType: VALIDATION_TYPES.TEXT,
|
||||
maxDate: VALIDATION_TYPES.DATE,
|
||||
minDate: VALIDATION_TYPES.DATE,
|
||||
maxDate: VALIDATION_TYPES.MAX_DATE,
|
||||
minDate: VALIDATION_TYPES.MIN_DATE,
|
||||
isRequired: VALIDATION_TYPES.BOOLEAN,
|
||||
// onDateSelected: VALIDATION_TYPES.ACTION_SELECTOR,
|
||||
// onDateRangeSelected: VALIDATION_TYPES.ACTION_SELECTOR,
|
||||
|
|
|
|||
|
|
@ -390,14 +390,8 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): ValidationResponse => {
|
||||
const today = moment()
|
||||
.hour(0)
|
||||
.minute(0)
|
||||
.second(0)
|
||||
.millisecond(0);
|
||||
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT;
|
||||
|
||||
const todayDateString = today.format(dateFormat);
|
||||
if (dateString === undefined) {
|
||||
return {
|
||||
isValid: false,
|
||||
|
|
@ -409,10 +403,16 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
};
|
||||
}
|
||||
const isValid = moment(dateString, dateFormat).isValid();
|
||||
const parsed = isValid ? dateString : todayDateString;
|
||||
if (!isValid) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: "",
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Date`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
isValid,
|
||||
parsed,
|
||||
parsed: dateString,
|
||||
message: isValid ? "" : `${WIDGET_TYPE_VALIDATION_ERROR}: Date`,
|
||||
};
|
||||
},
|
||||
|
|
@ -420,14 +420,7 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): ValidationResponse => {
|
||||
const today = moment()
|
||||
.hour(0)
|
||||
.minute(0)
|
||||
.second(0)
|
||||
.millisecond(0);
|
||||
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT;
|
||||
|
||||
const todayDateString = today.format(dateFormat);
|
||||
if (dateString === undefined) {
|
||||
return {
|
||||
isValid: false,
|
||||
|
|
@ -460,13 +453,109 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
const parsed = isValid ? dateString : todayDateString;
|
||||
|
||||
if (!isValid) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: "",
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Date R`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
isValid,
|
||||
parsed,
|
||||
message: isValid ? "" : `${WIDGET_TYPE_VALIDATION_ERROR}: Date R`,
|
||||
isValid: isValid,
|
||||
parsed: dateString,
|
||||
message: "",
|
||||
};
|
||||
},
|
||||
[VALIDATION_TYPES.MIN_DATE]: (
|
||||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): ValidationResponse => {
|
||||
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT;
|
||||
if (dateString === undefined) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: "",
|
||||
message:
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat
|
||||
? props.dateFormat
|
||||
: "",
|
||||
};
|
||||
}
|
||||
const parsedMinDate = moment(dateString, dateFormat);
|
||||
let isValid = parsedMinDate.isValid();
|
||||
if (!props.defaultDate) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: dateString,
|
||||
message: "",
|
||||
};
|
||||
}
|
||||
const parsedDefaultDate = moment(props.defaultDate, dateFormat);
|
||||
|
||||
if (
|
||||
isValid &&
|
||||
parsedDefaultDate.isValid() &&
|
||||
parsedDefaultDate.isBefore(parsedMinDate)
|
||||
) {
|
||||
isValid = false;
|
||||
}
|
||||
if (!isValid) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: "",
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Date R`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: dateString,
|
||||
message: "",
|
||||
};
|
||||
},
|
||||
[VALIDATION_TYPES.MAX_DATE]: (
|
||||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): ValidationResponse => {
|
||||
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT;
|
||||
if (dateString === undefined) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: "",
|
||||
message:
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat
|
||||
? props.dateFormat
|
||||
: "",
|
||||
};
|
||||
}
|
||||
const parsedMaxDate = moment(dateString, dateFormat);
|
||||
let isValid = parsedMaxDate.isValid();
|
||||
if (!props.defaultDate) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: dateString,
|
||||
message: "",
|
||||
};
|
||||
}
|
||||
const parsedDefaultDate = moment(props.defaultDate, dateFormat);
|
||||
|
||||
if (
|
||||
isValid &&
|
||||
parsedDefaultDate.isValid() &&
|
||||
parsedDefaultDate.isAfter(parsedMaxDate)
|
||||
) {
|
||||
isValid = false;
|
||||
}
|
||||
if (!isValid) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: "",
|
||||
message: `${WIDGET_TYPE_VALIDATION_ERROR}: Date R`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
isValid: isValid,
|
||||
parsed: dateString,
|
||||
message: "",
|
||||
};
|
||||
},
|
||||
[VALIDATION_TYPES.ACTION_SELECTOR]: (value: any): ValidationResponse => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user