diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts index 7af8b36b65b..db8a6dd278e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts @@ -206,6 +206,44 @@ describe('DsDatePickerComponent test suite', () => { }); }); + describe('when init model value is a Date object', () => { + beforeEach(() => { + dateFixture = TestBed.createComponent(DsDatePickerComponent); + dateComp = dateFixture.componentInstance; + dateComp.group = DATE_TEST_GROUP; + dateComp.model = new DynamicDsDatePickerModel(DATE_TEST_MODEL_CONFIG); + dateComp.model.value = new Date(Date.UTC(1983, 10, 18)); + dateFixture.detectChanges(); + }); + + it('should init component properly from a Date object', () => { + expect(dateComp.year).toBe(1983); + expect(dateComp.month).toBe(11); + expect(dateComp.day).toBe(18); + expect(dateComp.disabledMonth).toBeFalsy(); + expect(dateComp.disabledDay).toBeFalsy(); + }); + }); + + describe('when init model value is a NgbDateStruct-like object', () => { + beforeEach(() => { + dateFixture = TestBed.createComponent(DsDatePickerComponent); + dateComp = dateFixture.componentInstance; + dateComp.group = DATE_TEST_GROUP; + dateComp.model = new DynamicDsDatePickerModel(DATE_TEST_MODEL_CONFIG); + dateComp.model.value = { year: 1983, month: 11, day: 18 }; + dateFixture.detectChanges(); + }); + + it('should init component properly from a NgbDateStruct-like object', () => { + expect(dateComp.year).toBe(1983); + expect(dateComp.month).toBe(11); + expect(dateComp.day).toBe(18); + expect(dateComp.disabledMonth).toBeFalsy(); + expect(dateComp.disabledDay).toBeFalsy(); + }); + }); + describe('when init model value is not empty', () => { beforeEach(() => { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts index f0475fdf61a..674a6e0bbf2 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts @@ -14,6 +14,7 @@ import { FormsModule, UntypedFormGroup, } from '@angular/forms'; +import { dateValueToString } from '@dspace/shared/utils/date.util'; import { hasValue } from '@dspace/shared/utils/empty.util'; import { DynamicFormControlComponent, @@ -89,9 +90,7 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement this.initialDay = now.getUTCDate(); if (this.model && this.model.value !== null) { - // todo: model value could object or Date according to its type annotation - // eslint-disable-next-line @typescript-eslint/no-base-to-string - const values = this.model.value.toString().split(DS_DATE_PICKER_SEPARATOR); + const values = dateValueToString(this.model.value).split(DS_DATE_PICKER_SEPARATOR); if (values.length > 0) { this.initialYear = parseInt(values[0], 10); this.year = this.initialYear; diff --git a/src/app/shared/form/builder/parsers/date-field-parser.ts b/src/app/shared/form/builder/parsers/date-field-parser.ts index 0e0f3efd5bc..4d59b6793b9 100644 --- a/src/app/shared/form/builder/parsers/date-field-parser.ts +++ b/src/app/shared/form/builder/parsers/date-field-parser.ts @@ -1,4 +1,5 @@ import { FormFieldMetadataValueObject } from '@dspace/core/shared/form/models/form-field-metadata-value.model'; +import { dateValueToString } from '@dspace/shared/utils/date.util'; import { isNotEmpty } from '@dspace/shared/utils/empty.util'; import { DS_DATE_PICKER_SEPARATOR } from '../ds-dynamic-form-ui/models/date-picker/date-picker.component'; @@ -19,9 +20,7 @@ export class DateFieldParser extends FieldParser { this.setValues(inputDateModelConfig as any, fieldValue); // Init Data and validity check if (isNotEmpty(inputDateModelConfig.value)) { - // todo: model value could be object or Date according to its type annotation - // eslint-disable-next-line @typescript-eslint/no-base-to-string - const value = inputDateModelConfig.value.toString(); + const value = dateValueToString(inputDateModelConfig.value); if (value.length >= 4) { const valuesArray = value.split(DS_DATE_PICKER_SEPARATOR); if (valuesArray.length < 4) { diff --git a/src/app/utils/date.util.spec.ts b/src/app/utils/date.util.spec.ts index 6f41fbf17c3..8b3a6b3155f 100644 --- a/src/app/utils/date.util.spec.ts +++ b/src/app/utils/date.util.spec.ts @@ -2,6 +2,7 @@ import { dateToISOFormat, dateToNgbDateStruct, dateToString, + dateValueToString, isValidDate, yearFromString, } from './date.util'; @@ -93,6 +94,24 @@ describe('Date Utils', () => { }); }); + describe('dateValueToString', () => { + it('should return the same string when given a string', () => { + expect(dateValueToString('1983-11-18')).toEqual('1983-11-18'); + }); + it('should return YYYY-MM-DD when given a Date object', () => { + expect(dateValueToString(new Date(Date.UTC(1983, 10, 18)))).toEqual('1983-11-18'); + }); + it('should return YYYY-MM-DD when given a NgbDateStruct-like object', () => { + expect(dateValueToString({ year: 1983, month: 11, day: 18 })).toEqual('1983-11-18'); + }); + it('should throw an error for an arbitrary object', () => { + expect(() => dateValueToString({ foo: 'bar' })).toThrowError(/Unsupported date value type/); + }); + it('should throw an error for an empty object', () => { + expect(() => dateValueToString({})).toThrowError(/Unsupported date value type/); + }); + }); + describe('yearFromString', () => { it('should return year from YYYY string', () => { expect(yearFromString('2022')).toEqual(2022); diff --git a/src/app/utils/date.util.ts b/src/app/utils/date.util.ts index 7450687adad..d74f5cf703f 100644 --- a/src/app/utils/date.util.ts +++ b/src/app/utils/date.util.ts @@ -108,3 +108,29 @@ export function yearFromString(date: string) { return isValidDate(date) ? new Date(date).getUTCFullYear() : null; } +/** + * Converts a date model value (string | Date | object) to a YYYY-MM-DD formatted string. + * + * The dynamic form library defines date values as string | object | Date. + * This function safely handles all supported types and throws an informative + * error if an unsupported object type is encountered. + * + * @param value The date value to convert + * @returns The date as a string (e.g. "1983-11-18") + * @throws Error if value is an object without year/month/day properties + */ +export function dateValueToString(value: string | Date | object): string { + if (typeof value === 'string') { + return value; + } + if (value instanceof Date) { + return dateToString(value); + } + if (isNgbDateStruct(value)) { + return dateToString(value as NgbDateStruct); + } + throw new Error( + `Unsupported date value type: expected a string, Date, or object with {year, month, day} properties, but received: ${JSON.stringify(value)}`, + ); +} +