diff --git a/libs/components/datetime/src/lib/modules/datepicker/datepicker-input-fuzzy.directive.ts b/libs/components/datetime/src/lib/modules/datepicker/datepicker-input-fuzzy.directive.ts index e24c9d2a10..da37d68793 100644 --- a/libs/components/datetime/src/lib/modules/datepicker/datepicker-input-fuzzy.directive.ts +++ b/libs/components/datetime/src/lib/modules/datepicker/datepicker-input-fuzzy.directive.ts @@ -425,6 +425,10 @@ export class SkyFuzzyDatepickerInputDirective validationError = { skyFuzzyDate: { maxDate: value, + maxDateFormatted: this.#dateFormatter.format( + fuzzyDateRange.endDate, + this.dateFormat, + ), }, }; } @@ -439,6 +443,10 @@ export class SkyFuzzyDatepickerInputDirective validationError = { skyFuzzyDate: { minDate: value, + minDateFormatted: this.#dateFormatter.format( + fuzzyDateRange.startDate, + this.dateFormat, + ), }, }; } diff --git a/libs/components/datetime/src/lib/modules/datepicker/datepicker-input.directive.ts b/libs/components/datetime/src/lib/modules/datepicker/datepicker-input.directive.ts index 4f4f16a866..c095d824ff 100644 --- a/libs/components/datetime/src/lib/modules/datepicker/datepicker-input.directive.ts +++ b/libs/components/datetime/src/lib/modules/datepicker/datepicker-input.directive.ts @@ -395,6 +395,10 @@ export class SkyDatepickerInputDirective return { skyDate: { minDate, + minDateFormatted: this.#dateFormatter.format( + minDate, + this.dateFormat, + ), }, }; } @@ -409,6 +413,10 @@ export class SkyDatepickerInputDirective return { skyDate: { maxDate, + maxDateFormatted: this.#dateFormatter.format( + maxDate, + this.dateFormat, + ), }, }; } diff --git a/libs/components/datetime/src/lib/modules/datepicker/datepicker.component.spec.ts b/libs/components/datetime/src/lib/modules/datepicker/datepicker.component.spec.ts index 329d880474..2bb0976b4c 100644 --- a/libs/components/datetime/src/lib/modules/datepicker/datepicker.component.spec.ts +++ b/libs/components/datetime/src/lib/modules/datepicker/datepicker.component.spec.ts @@ -923,6 +923,12 @@ describe('datepicker', () => { setInputElementValue(fixture.nativeElement, '5/26/2017', fixture); expect(ngModel.valid).toBe(false); + expect(ngModel.errors).toEqual({ + skyDate: { + maxDate: component.maxDate, + maxDateFormatted: '05/25/2017', + }, + }); })); it('should handle change below min date', fakeAsync(() => { @@ -933,6 +939,12 @@ describe('datepicker', () => { setInputElementValue(fixture.nativeElement, '5/1/2017', fixture); expect(ngModel.valid).toBe(false); + expect(ngModel.errors).toEqual({ + skyDate: { + minDate: component.minDate, + minDateFormatted: '05/04/2017', + }, + }); })); it('should pass max date to calendar', fakeAsync(() => { diff --git a/libs/components/datetime/src/lib/modules/datepicker/fuzzy-date.service.ts b/libs/components/datetime/src/lib/modules/datepicker/fuzzy-date.service.ts index 1d4e230a33..8705d34e76 100644 --- a/libs/components/datetime/src/lib/modules/datepicker/fuzzy-date.service.ts +++ b/libs/components/datetime/src/lib/modules/datepicker/fuzzy-date.service.ts @@ -23,6 +23,8 @@ interface SkyFuzzyDateRange { years: string; months: string; days: string; + startDate: Date; + endDate: Date; valid: boolean; } @@ -307,8 +309,8 @@ export class SkyFuzzyDateService implements OnDestroy { startFuzzyDate: SkyFuzzyDate, endFuzzyDate: SkyFuzzyDate, ): SkyFuzzyDateRange { - let start; - let end; + const start = this.getMomentFromFuzzyDate(startFuzzyDate); + const end = this.getMomentFromFuzzyDate(endFuzzyDate); let days; let months; let years; @@ -320,9 +322,6 @@ export class SkyFuzzyDateService implements OnDestroy { endFuzzyDate && endFuzzyDate.year ) { - start = this.getMomentFromFuzzyDate(startFuzzyDate); - end = this.getMomentFromFuzzyDate(endFuzzyDate); - years = end.diff(start, 'years'); months = end.diff(start, 'months'); days = end.diff(start, 'days'); @@ -333,6 +332,8 @@ export class SkyFuzzyDateService implements OnDestroy { years: years, months: months, days: days, + startDate: start.toDate(), + endDate: end.toDate(), valid: valid, }; } diff --git a/libs/components/datetime/src/lib/modules/datepicker/fuzzy-datepicker.component.spec.ts b/libs/components/datetime/src/lib/modules/datepicker/fuzzy-datepicker.component.spec.ts index 6bb50c5d67..fd9315cdf9 100644 --- a/libs/components/datetime/src/lib/modules/datepicker/fuzzy-datepicker.component.spec.ts +++ b/libs/components/datetime/src/lib/modules/datepicker/fuzzy-datepicker.component.spec.ts @@ -1014,6 +1014,9 @@ describe('fuzzy datepicker input', () => { expect(ngModel.valid).toBe(false); expect(ngModel.touched).toBe(true); expect(ngModel.errors?.['skyFuzzyDate'].minDate).toBeTruthy(); + expect(ngModel.errors?.['skyFuzzyDate'].minDateFormatted).toEqual( + '02/15/2015', + ); setInputElementValue(nativeElement, '2/15/2015', fixture); @@ -1035,6 +1038,9 @@ describe('fuzzy datepicker input', () => { expect(ngModel.valid).toBe(false); expect(ngModel.errors?.['skyFuzzyDate'].maxDate).toBeTruthy(); + expect(ngModel.errors?.['skyFuzzyDate'].maxDateFormatted).toEqual( + '05/25/2017', + ); flush(); })); @@ -1048,6 +1054,9 @@ describe('fuzzy datepicker input', () => { expect(ngModel.valid).toBe(false); expect(ngModel.errors?.['skyFuzzyDate'].minDate).toBeTruthy(); + expect(ngModel.errors?.['skyFuzzyDate'].minDateFormatted).toEqual( + '05/04/2017', + ); flush(); })); diff --git a/libs/components/forms/src/assets/locales/resources_en_US.json b/libs/components/forms/src/assets/locales/resources_en_US.json index 594019e9ee..a663f66cf8 100644 --- a/libs/components/forms/src/assets/locales/resources_en_US.json +++ b/libs/components/forms/src/assets/locales/resources_en_US.json @@ -21,11 +21,11 @@ }, "skyux_form_error_date_max": { "_description": "Error message for a field with a date after max date", - "message": "Select or enter a date before the max date." + "message": "Select or enter a date on or before {0}." }, "skyux_form_error_date_min": { "_description": "Error message for a field with a date before min date", - "message": "Select or enter a date after the min date." + "message": "Select or enter a date on or after {0}." }, "skyux_form_error_fuzzy_date_future_disabled": { "_description": "Error message for a field with a in invalid fuzzy date in the future", @@ -37,11 +37,11 @@ }, "skyux_form_error_fuzzy_date_max_date": { "_description": "Error message for a field with a date after max fuzzy date", - "message": "Select or enter a date before the max date." + "message": "Select or enter a date on or before {0}." }, "skyux_form_error_fuzzy_date_min_date": { "_description": "Error message for a field with a date before min fuzzy date", - "message": "Select or enter a date after the min date." + "message": "Select or enter a date on or after {0}." }, "skyux_form_error_fuzzy_date_year_required": { "_description": "Error message for a field with a date without a year", diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors.component.html b/libs/components/forms/src/lib/modules/form-error/form-errors.component.html index 111f06349e..b69dd65e96 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-errors.component.html +++ b/libs/components/forms/src/lib/modules/form-error/form-errors.component.html @@ -27,14 +27,20 @@ @if (errors?.['skyDate'] && errors?.['skyDate']['minDate']) { } @if (errors?.['skyDate'] && errors?.['skyDate']['maxDate']) { } @@ -59,14 +65,22 @@ @if (errors?.['skyFuzzyDate'] && errors?.['skyFuzzyDate']['maxDate']) { } @if (errors?.['skyFuzzyDate'] && errors?.['skyFuzzyDate']['minDate']) { } diff --git a/libs/components/forms/src/lib/modules/form-error/form-errors.component.spec.ts b/libs/components/forms/src/lib/modules/form-error/form-errors.component.spec.ts index 6803ff27bd..77efb7921a 100644 --- a/libs/components/forms/src/lib/modules/form-error/form-errors.component.spec.ts +++ b/libs/components/forms/src/lib/modules/form-error/form-errors.component.spec.ts @@ -44,12 +44,12 @@ describe('Form errors component', () => { required: true, maxlength: true, minlength: true, - skyDate: { invalid: true, minDate: true, maxDate: true }, + skyDate: { invalid: true, minDate: '01/01/2024', maxDate: '01/01/2022' }, skyFuzzyDate: { futureDisabled: true, invalid: true, - maxDate: true, - minDate: true, + maxDate: '01/2023', + minDate: '01/2024', yearRequired: true, }, skyEmail: true, @@ -100,6 +100,57 @@ describe('Form errors component', () => { }); }); + it('should include the minimum or maximum date in the date error messages', () => { + componentInstance.errors = { + skyDate: { + invalid: true, + maxDate: new Date('01/01/2025'), + maxDateFormatted: '01/01/2025', + minDate: new Date('01/01/2024'), + minDateFormatted: '01/01/2024', + }, + skyFuzzyDate: { + futureDisabled: true, + invalid: true, + maxDate: new Date('01/01/2021'), + maxDateFormatted: '01/01/2021', + minDate: new Date('01/01/2020'), + minDateFormatted: '01/01/2020', + yearRequired: true, + }, + }; + + componentInstance.dirty = true; + componentInstance.touched = true; + fixture.detectChanges(); + + const minDateErrorMessage = fixture.nativeElement.querySelector( + `sky-form-error[errorName='minDate'] .sky-status-indicator-message`, + ); + const maxDateErrorMessage = fixture.nativeElement.querySelector( + `sky-form-error[errorName='maxDate'] .sky-status-indicator-message`, + ); + const fuzzyMinDateErrorMessage = fixture.nativeElement.querySelector( + `sky-form-error[errorName='fuzzyMinDate'] .sky-status-indicator-message`, + ); + const fuzzyMaxDateErrorMessage = fixture.nativeElement.querySelector( + `sky-form-error[errorName='fuzzyMaxDate'] .sky-status-indicator-message`, + ); + + expect(minDateErrorMessage.textContent).toEqual( + 'Select or enter a date on or after 01/01/2024.', + ); + expect(maxDateErrorMessage.textContent).toEqual( + 'Select or enter a date on or before 01/01/2025.', + ); + expect(fuzzyMinDateErrorMessage.textContent).toEqual( + 'Select or enter a date on or after 01/01/2020.', + ); + expect(fuzzyMaxDateErrorMessage.textContent).toEqual( + 'Select or enter a date on or before 01/01/2021.', + ); + }); + it('should render custom errors when there are no known errors and labelText is present regardless of touched or dirty', () => { componentInstance.touched = true; fixture.detectChanges(); diff --git a/libs/components/forms/src/lib/modules/shared/sky-forms-resources.module.ts b/libs/components/forms/src/lib/modules/shared/sky-forms-resources.module.ts index 786fc6aa56..954114af13 100644 --- a/libs/components/forms/src/lib/modules/shared/sky-forms-resources.module.ts +++ b/libs/components/forms/src/lib/modules/shared/sky-forms-resources.module.ts @@ -29,10 +29,10 @@ const RESOURCES: Record = { }, skyux_form_error_date: { message: 'Select or enter a valid date.' }, skyux_form_error_date_max: { - message: 'Select or enter a date before the max date.', + message: 'Select or enter a date on or before {0}.', }, skyux_form_error_date_min: { - message: 'Select or enter a date after the min date.', + message: 'Select or enter a date on or after {0}.', }, skyux_form_error_fuzzy_date_future_disabled: { message: 'Future dates are disabled, select or enter a date in the past.', @@ -41,10 +41,10 @@ const RESOURCES: Record = { message: 'Select or enter a valid date.', }, skyux_form_error_fuzzy_date_max_date: { - message: 'Select or enter a date before the max date.', + message: 'Select or enter a date on or before {0}.', }, skyux_form_error_fuzzy_date_min_date: { - message: 'Select or enter a date after the min date.', + message: 'Select or enter a date on or after {0}.', }, skyux_form_error_fuzzy_date_year_required: { message: 'Year is required.' }, skyux_form_error_email: {