Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ACS-5857] Moment to Date-Fns Migration for adfMomentDate Pipe. #8924

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/core/src/lib/common/utils/date-fns-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,13 @@ describe('Date Format Translations', () => {

expect(result).toEqual(expectedParsedDate);
});

it('should add seconds to a date time value', () => {
const inputDateTime = '2023-09-02T10:00:000Z';
const expectedUpdatedValue = '2023-09-02T10:00:00.000Z';

const result = DateFnsUtils.addSeconds(inputDateTime);

expect(result).toEqual(expectedUpdatedValue);
});
});
42 changes: 37 additions & 5 deletions lib/core/src/lib/common/utils/date-fns-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ export class DateFnsUtils {
D: 'd',
Y: 'y',
A: 'a',
ll: 'PP'
ll: 'PP',
Z: ` zzzz`,
T: `'T'`
};

/**
Expand All @@ -97,7 +99,8 @@ export class DateFnsUtils {
d: 'D',
y: 'Y',
a: 'A',
PP: 'll'
PP: 'll',
xxx: 'Z'
};

/**
Expand All @@ -107,6 +110,17 @@ export class DateFnsUtils {
* @returns The equivalent date-fns format string.
*/
static convertMomentToDateFnsFormat(dateDisplayFormat: string): string {
// Check if 'A' is present in the format string
let containsA;
if (dateDisplayFormat) {
containsA = dateDisplayFormat.includes('A');
}

// Replace 'HH' with 'hh' if 'A' is also present
if (containsA) {
dateDisplayFormat = dateDisplayFormat.replace(/HH/g, 'hh');
}

if (dateDisplayFormat && dateDisplayFormat.trim() !== '') {
for (const [search, replace] of Object.entries(this.momentToDateFnsMap)) {
dateDisplayFormat = dateDisplayFormat.replace(new RegExp(search, 'g'), replace);
Expand Down Expand Up @@ -149,11 +163,29 @@ export class DateFnsUtils {
/**
* Parses a date string using the specified date format.
*
* @param value - The date string to parse.
* @param date - The date string to parse.
* @param dateFormat - The date format string to use for parsing.
* @returns The parsed Date object.
*/
static parseDate(value: string, dateFormat: string): Date {
return parse(value, this.convertMomentToDateFnsFormat(dateFormat), new Date());
static parseDate(date: Date | string, dateFormat: string): Date {
if (date instanceof Date) {
date = date.toISOString();
}
return parse(date, this.convertMomentToDateFnsFormat(dateFormat), new Date());
}

/**
* Adds seconds to a date time value represented as a string in the format 'YYYY-MM-DDTHH:mm:ssZ'.
*
* @param value - The input time value to which seconds will be added.
* @returns - A string representing the input date time value with seconds added.
*/
static addSeconds(value: string): string {
const colonIndex: number = value.lastIndexOf(':');
const updatedValue = value.slice(0, colonIndex) + ':' + value.slice(colonIndex + 1);
const dateParts: string[] = updatedValue.split(':');
dateParts[2] = '00.' + dateParts[2];
value = dateParts.join(':');
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

import { DateFnsUtils } from '../../../../common/utils/date-fns-utils';
import { ErrorMessageModel } from './error-message.model';
import { FormFieldOption } from './form-field-option';
import { FormFieldTypes } from './form-field-types';
Expand All @@ -35,7 +36,6 @@ import {
} from './form-field-validator';
import { FormFieldModel } from './form-field.model';
import { FormModel } from './form.model';
declare let moment: any;

describe('FormFieldValidator', () => {
describe('RequiredFieldValidator', () => {
Expand Down Expand Up @@ -708,7 +708,7 @@ describe('FormFieldValidator', () => {

it('should take into account that max value is in UTC and NOT fail validating value checking the time', () => {
const maxValueFromActivitiInput = '31-3-2018 12:00 AM';
const maxValueSavedInForm = moment(maxValueFromActivitiInput, 'DD-M-YYYY hh:mm A').utc().format();
const maxValueSavedInForm = DateFnsUtils.parseDate(maxValueFromActivitiInput, 'DD-M-YYYY hh:mm A').toISOString();

const localValidValue = '2018-3-30 11:59 PM';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are again changing the test data coming from backend, do not touch this value


Expand All @@ -723,7 +723,7 @@ describe('FormFieldValidator', () => {

it('should take into account that max value is in UTC and fail validating value checking the time', () => {
const maxValueFromActivitiInput = '31-3-2018 12:00 AM';
const maxValueSavedInForm = moment(maxValueFromActivitiInput, 'DD-M-YYYY hh:mm A').utc().format();
const maxValueSavedInForm = DateFnsUtils.parseDate(maxValueFromActivitiInput, 'DD-M-YYYY hh:mm A').toISOString();

const localInvalidValue = '2018-3-31 12:01 AM';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modifying server related value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We changed this to accomodate the suggested parseISO() approach used in form-field-model.ts e6e0b27#diff-231637c71df1cd50fe2ef9ba319639d7eeb28657b17f552fc979be0b9f508cd0R357.

We were not attempting to change the data here, but parsing it so that it's compatible with .ts logic.

In the previous approach where we were using parseDate(), where we did not need any changes in the test case e6e0b27#diff-231637c71df1cd50fe2ef9ba319639d7eeb28657b17f552fc979be0b9f508cd0L357

upon revisiting this I think, the previous approach was better as no modifications were needed in the test case then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const localInvalidValue = '2018-3-31 12:01 AM'; means invalid date as string, and you are parsing it and converting to iso


Expand Down Expand Up @@ -833,7 +833,7 @@ describe('FormFieldValidator', () => {

it('should take into account that min value is in UTC and NOT fail validating value checking the time', () => {
const minValueFromActivitiInput = '02-3-2018 06:00 AM';
const minValueSavedInForm = moment(minValueFromActivitiInput, 'DD-M-YYYY hh:mm A').utc().format();
const minValueSavedInForm = DateFnsUtils.parseDate(minValueFromActivitiInput, 'DD-M-YYYY hh:mm A').toISOString();

const localValidValue = '2018-3-02 06:01 AM';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the test data should not be changed, it's the activity form field model... the purpose of validator is to do the magic inside and validate what's coming into...


Expand All @@ -848,7 +848,7 @@ describe('FormFieldValidator', () => {

it('should take into account that min value is in UTC and fail validating value checking the time', () => {
const minValueFromActivitiInput = '02-3-2018 06:00 AM';
const minValueSavedInForm = moment(minValueFromActivitiInput, 'DD-M-YYYY hh:mm A').utc().format();
const minValueSavedInForm = DateFnsUtils.parseDate(minValueFromActivitiInput, 'DD-M-YYYY hh:mm A').toISOString();

const localInvalidValue = '2018-3-02 05:59 AM';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified test data


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import moment from 'moment';
import { FormFieldTypes } from './form-field-types';
import { isNumberValue } from './form-field-utils';
import { FormFieldModel } from './form-field.model';
import { isAfter, isBefore, isValid } from 'date-fns';
import { DateFnsUtils } from '../../../../common/utils/date-fns-utils';
rbahirsheth marked this conversation as resolved.
Show resolved Hide resolved

export interface FormFieldValidator {

Expand Down Expand Up @@ -179,8 +181,14 @@ export class DateTimeFieldValidator implements FormFieldValidator {
// Validates that the input string is a valid date formatted as <dateFormat> (default D-M-YYYY)
static isValidDate(inputDate: string, dateFormat: string = 'YYYY-MM-DD HH:mm'): boolean {
if (inputDate) {
const d = moment(inputDate, dateFormat, true);
return d.isValid();
let dateTime = DateFnsUtils.parseDate(inputDate, dateFormat);

if (!isValid(dateTime) && dateFormat !== 'YYYY-MM-DD HH:mm') {
dateFormat = 'YYYY-MM-DD HH:mm';
dateTime = DateFnsUtils.parseDate(inputDate, dateFormat);
}

return isValid(dateTime);
}

return false;
Expand All @@ -192,10 +200,10 @@ export class DateTimeFieldValidator implements FormFieldValidator {

validate(field: FormFieldModel): boolean {
if (this.isSupported(field) && field.value && field.isVisible) {
if (DateFieldValidator.isValidDate(field.value, field.dateDisplayFormat)) {
if (DateTimeFieldValidator.isValidDate(field.value, field.dateDisplayFormat)) {
return true;
}
field.validationSummary.message = field.dateDisplayFormat;
field.validationSummary.message = DateFnsUtils.convertDateFnsToMomentFormat(field.dateDisplayFormat);
return false;
}
return true;
Expand All @@ -212,18 +220,18 @@ export abstract class BoundaryDateFieldValidator implements FormFieldValidator {
];

validate(field: FormFieldModel): boolean {
let isValid = true;
let isFieldValid = true;
if (this.isSupported(field) && field.value && field.isVisible) {
const dateFormat = field.dateDisplayFormat;

if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
isValid = false;
isFieldValid = false;
} else {
isValid = this.checkDate(field, dateFormat);
isFieldValid = this.checkDate(field, dateFormat);
}
}
return isValid;
return isFieldValid;
}

extractDateFormat(date: string): string {
Expand All @@ -240,7 +248,7 @@ export class MinDateFieldValidator extends BoundaryDateFieldValidator {

checkDate(field: FormFieldModel, dateFormat: string): boolean {

let isValid = true;
let isFieldValid = true;
// remove time and timezone info
let fieldValueData;
if (typeof field.value === 'string') {
Expand All @@ -255,9 +263,9 @@ export class MinDateFieldValidator extends BoundaryDateFieldValidator {
if (fieldValueData.isBefore(min)) {
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
field.validationSummary.attributes.set('minValue', min.format(field.dateDisplayFormat).toLocaleUpperCase());
isValid = false;
isFieldValid = false;
}
return isValid;
return isFieldValid;
}

isSupported(field: FormFieldModel): boolean {
Expand All @@ -270,7 +278,7 @@ export class MaxDateFieldValidator extends BoundaryDateFieldValidator {

checkDate(field: FormFieldModel, dateFormat: string): boolean {

let isValid = true;
let isFieldValid = true;
// remove time and timezone info
let fieldValueData;
if (typeof field.value === 'string') {
Expand All @@ -285,9 +293,9 @@ export class MaxDateFieldValidator extends BoundaryDateFieldValidator {
if (fieldValueData.isAfter(max)) {
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
field.validationSummary.attributes.set('maxValue', max.format(field.dateDisplayFormat).toLocaleUpperCase());
isValid = false;
isFieldValid = false;
}
return isValid;
return isFieldValid;
}

isSupported(field: FormFieldModel): boolean {
Expand All @@ -309,36 +317,36 @@ export class MinDateTimeFieldValidator implements FormFieldValidator {
}

validate(field: FormFieldModel): boolean {
let isValid = true;
let isFieldValid = true;
if (this.isSupported(field) && field.value && field.isVisible) {
const dateFormat = field.dateDisplayFormat;

if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
if (!DateTimeFieldValidator.isValidDate(field.value, dateFormat)) {
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
isValid = false;
isFieldValid = false;
} else {
isValid = this.checkDateTime(field, dateFormat);
isFieldValid = this.checkDateTime(field, dateFormat);
}
}
return isValid;
return isFieldValid;
}

private checkDateTime(field: FormFieldModel, dateFormat: string): boolean {
let isValid = true;
let isFieldValid = true;
let fieldValueDate;
if (typeof field.value === 'string') {
fieldValueDate = moment(field.value, dateFormat);
fieldValueDate = DateFnsUtils.parseDate(field.value, dateFormat);
} else {
fieldValueDate = field.value;
}
const min = moment(field.minValue, this.MIN_DATETIME_FORMAT);
const min = DateFnsUtils.formatDate(new Date(field.minValue), this.MIN_DATETIME_FORMAT);

if (fieldValueDate.isBefore(min)) {
if (isBefore(fieldValueDate, new Date(min))) {
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`;
field.validationSummary.attributes.set('minValue', min.format(field.dateDisplayFormat).replace(':', '-'));
isValid = false;
field.validationSummary.attributes.set('minValue', DateFnsUtils.formatDate(new Date(min), field.dateDisplayFormat).replace(':', '-'));
isFieldValid = false;
}
return isValid;
return isFieldValid;
}
}

Expand All @@ -355,37 +363,38 @@ export class MaxDateTimeFieldValidator implements FormFieldValidator {
}

validate(field: FormFieldModel): boolean {
let isValid = true;
let isFieldValid = true;
if (this.isSupported(field) && field.value && field.isVisible) {
const dateFormat = field.dateDisplayFormat;

if (!DateFieldValidator.isValidDate(field.value, dateFormat)) {
if (!DateTimeFieldValidator.isValidDate(field.value, dateFormat)) {
field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE';
isValid = false;
isFieldValid = false;
} else {
isValid = this.checkDateTime(field, dateFormat);
isFieldValid = this.checkDateTime(field, dateFormat);
}
}
return isValid;
return isFieldValid;
}

private checkDateTime(field: FormFieldModel, dateFormat: string): boolean {
let isValid = true;
let isFieldValid = true;
let fieldValueDate;

if (typeof field.value === 'string') {
fieldValueDate = moment(field.value, dateFormat);
fieldValueDate = DateFnsUtils.parseDate(field.value, dateFormat);
} else {
fieldValueDate = field.value;
}
const max = moment(field.maxValue, this.MAX_DATETIME_FORMAT);
const max = DateFnsUtils.formatDate(new Date(field.maxValue), this.MAX_DATETIME_FORMAT);


if (fieldValueDate.isAfter(max)) {
if (isAfter(fieldValueDate, new Date(max))) {
field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`;
field.validationSummary.attributes.set('maxValue', max.format(field.dateDisplayFormat).replace(':', '-'));
isValid = false;
field.validationSummary.attributes.set('maxValue', DateFnsUtils.formatDate(new Date(max), field.dateDisplayFormat).replace(':', '-'));
isFieldValid = false;
}
return isValid;
return isFieldValid;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import moment from 'moment';
import { FormFieldTypes } from './form-field-types';
import { FormFieldModel } from './form-field.model';
import { FormModel } from './form.model';
import { DateFnsUtils } from '../../../../common/utils/date-fns-utils';
rbahirsheth marked this conversation as resolved.
Show resolved Hide resolved

describe('FormFieldModel', () => {

Expand Down Expand Up @@ -304,9 +305,12 @@ describe('FormFieldModel', () => {
dateDisplayFormat: 'YYYY-MM-DD HH:mm'
});

const currentDateTime = moment(new Date());
const expectedDateTime = moment.utc(currentDateTime).format('YYYY-MM-DD HH:mm');
const expectedDateTimeFormat = `${currentDateTime.utc().format('YYYY-MM-DDTHH:mm:00')}.000Z`;
const currentDateTime = new Date();
const formattedDate = DateFnsUtils.formatDate(currentDateTime, 'YYYY-MM-DD');
const formattedTime = DateFnsUtils.formatDate(currentDateTime, 'HH:mm');

const expectedDateTime = DateFnsUtils.formatDate(currentDateTime, 'YYYY-MM-DD HH:mm');
const expectedDateTimeFormat = formattedDate + `T${formattedTime}:00.000Z`;

expect(field.value).toBe(expectedDateTime);
expect(form.values['datetime']).toEqual(expectedDateTimeFormat);
Expand Down
Loading
Loading