Skip to content

Commit

Permalink
fix(date-picker): ensure that time portion of Date value is preserv…
Browse files Browse the repository at this point in the history
…ed during initial render and dropdown calendar selection
  • Loading branch information
DRiFTy17 committed Sep 19, 2024
1 parent 2877b4f commit 58282b1
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/lib/core/utils/date-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export function isSameDate(first?: Date | null, second?: Date | null): boolean {
} else if (!isValidDate(first) || !isValidDate(second)) {
return false;
}
return first.setHours(0, 0, 0, 0) === second.setHours(0, 0, 0, 0);
return new Date(first).setHours(0, 0, 0, 0) === new Date(second).setHours(0, 0, 0, 0);
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/lib/date-picker/date-picker-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class DatePickerCore extends BaseDatePickerCore<IDatePickerAdapter, Date

protected _onToday(): void {
const today = new Date();
today.setHours(0, 0, 0, 0);
this._tryMergeCurrentTime(today);
this._onDateSelected({ date: today, selected: true, type: 'date' });
}

Expand Down Expand Up @@ -76,6 +76,8 @@ export class DatePickerCore extends BaseDatePickerCore<IDatePickerAdapter, Date
this._closeCalendar(true);
}

this._tryMergeCurrentTime(value);

if (!this._emitChangeEvent(value)) {
return;
}
Expand Down Expand Up @@ -132,6 +134,7 @@ export class DatePickerCore extends BaseDatePickerCore<IDatePickerAdapter, Date
protected _handleInput(value: string): void {
const sanitizedValue = this._getSanitizedDateString(value);
const date = this._coerceDateValue(sanitizedValue);
this._tryMergeCurrentTime(date);
if (this._masked) {
this._adapter.emitInputEvent(DATE_PICKER_CONSTANTS.events.INPUT, sanitizedValue);
}
Expand All @@ -154,6 +157,13 @@ export class DatePickerCore extends BaseDatePickerCore<IDatePickerAdapter, Date
}
}

private _tryMergeCurrentTime(date: Date | null | undefined): void {
if (!date || !this._value) {
return;
}
date.setHours(this._value.getHours(), this._value.getMinutes(), this._value.getSeconds(), this._value.getMilliseconds());
}

private _applyValue(): void {
this._setFormattedInputValue();
if (this._open) {
Expand Down
19 changes: 19 additions & 0 deletions src/lib/date-range-picker/date-range-picker-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export class DateRangePickerCore extends BaseDatePickerCore<IDateRangePickerAdap

protected _onToday(): void {
const today = new Date();
this._tryMergeCurrentTime({ from: today });
const range = this._open ? new DateRange({ from: this._from || today, to: this._to || undefined }) : new DateRange({ from: today });
if (!this._isDateRangeAcceptable(range)) {
return;
Expand Down Expand Up @@ -204,6 +205,8 @@ export class DateRangePickerCore extends BaseDatePickerCore<IDateRangePickerAdap
this._closeCalendar(true);
}

this._tryMergeCurrentTime(value);

if (!this._emitChangeEvent(value ?? null)) {
return;
}
Expand Down Expand Up @@ -300,6 +303,7 @@ export class DateRangePickerCore extends BaseDatePickerCore<IDateRangePickerAdap
protected _handleInput(value: string): void {
const sanitizedValue = this._getSanitizedDateString(value);
const date = this._coerceDateValue(sanitizedValue);
this._tryMergeCurrentTime({ from: date as Date | undefined });
if (this._masked) {
this._adapter.emitInputEvent(DATE_RANGE_PICKER_CONSTANTS.events.INPUT, sanitizedValue);
}
Expand All @@ -311,6 +315,7 @@ export class DateRangePickerCore extends BaseDatePickerCore<IDateRangePickerAdap
private _handleToInput(value: string): void {
const sanitizedValue = this._getSanitizedDateString(value);
const date = this._coerceDateValue(sanitizedValue);
this._tryMergeCurrentTime({ to: date as Date | undefined });
if (this._masked) {
this._adapter.emitToInputEvent(DATE_RANGE_PICKER_CONSTANTS.events.INPUT, sanitizedValue);
}
Expand Down Expand Up @@ -385,6 +390,20 @@ export class DateRangePickerCore extends BaseDatePickerCore<IDateRangePickerAdap
}
}

private _tryMergeCurrentTime(range: Partial<DateRange> | null | undefined): void {
if (!range || !this._value || (!this._value.from && !this._value.to)) {
return;
}

if (range.from && this._value.from && this._value.from instanceof Date) {
range.from.setHours(this._value.from.getHours(), this._value.from.getMinutes(), this._value.from.getSeconds(), this._value.from.getMilliseconds());
}

if (range.to && this._value.to && this._value.to instanceof Date) {
range.to.setHours(this._value.to.getHours(), this._value.to.getMinutes(), this._value.to.getSeconds(), this._value.to.getMilliseconds());
}
}

public get value(): IDatePickerRange | null | undefined {
return { from: this.from, to: this.to };
}
Expand Down
19 changes: 14 additions & 5 deletions src/test/spec/date-picker/date-picker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ describe('DatePickerComponent', function(this: ITestContext) {
expect((<Date>calendar.value).toDateString()).toEqual(date.toDateString());
});

it('should preserve timestamp from date value after initialization', async function(this: ITestContext) {
this.context = setupTestContext(true);
const dateStr = '2024-01-01T10:17:23.000Z';
const date = new Date(dateStr);
this.context.component.value = date;
this.context.append();
await frame();

expect(this.context.component.value.toISOString()).toEqual(dateStr);
});

it('should open calendar in month of min date if min is after current month', function(this: ITestContext) {
this.context = setupTestContext(false);
const date = new Date();
Expand Down Expand Up @@ -1218,13 +1229,12 @@ describe('DatePickerComponent', function(this: ITestContext) {

const popup = getPopup(this.context.component);
const today = new Date();
today.setHours(0, 0, 0, 0);

expect(changeSpy).toHaveBeenCalledTimes(1);
expect(this.context.component.open).toBeFalse();
expect(popup).toBeNull('Expected popup to be removed');
expect(this.context.component.value).toBeInstanceOf(Date);
expect((this.context.component.value as Date)).toEqual(today);
expect((this.context.component.value as Date).toDateString()).toEqual(today.toDateString());
});

it('should set date to todays date when clicking today button a second time', async function(this: ITestContext) {
Expand All @@ -1240,13 +1250,12 @@ describe('DatePickerComponent', function(this: ITestContext) {

const popup = getPopup(this.context.component);
const today = new Date();
today.setHours(0, 0, 0, 0);

expect(changeSpy).toHaveBeenCalledTimes(1);
expect(this.context.component.open).toBeFalse();
expect(popup).toBeNull('Expected popup to be removed');
expect(this.context.component.value).toBeInstanceOf(Date);
expect((this.context.component.value as Date)).toEqual(today);
expect((this.context.component.value as Date).toDateString()).toEqual(today.toDateString());

openPopup(this.context.component);

Expand All @@ -1258,7 +1267,7 @@ describe('DatePickerComponent', function(this: ITestContext) {
expect(this.context.component.open).toBeFalse();
expect(popup).toBeNull('Expected popup to be removed');
expect(this.context.component.value).toBeInstanceOf(Date);
expect((this.context.component.value as Date)).toEqual(today);
expect((this.context.component.value as Date).toDateString()).toEqual(today.toDateString());
});

it('should remove value when clicking clear button', async function(this: ITestContext) {
Expand Down
14 changes: 14 additions & 0 deletions src/test/spec/date-range-picker/date-range-picker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,20 @@ describe('DateRangePickerComponent', function(this: ITestContext) {
expect((calendar.value as IDateRange).from).toEqual(date);
});

it('should preserve timestamp from date value after initialization', async function(this: ITestContext) {
this.context = setupTestContext();
const fromStr = '2024-01-01T10:17:23.000Z';
const from = new Date(fromStr);
const toStr = '2024-01-05T07:15:43.000Z';
const to = new Date(toStr);
this.context.component.value = { from, to };
this.context.append();
await frame();

expect((this.context.component.value.from as Date).toISOString()).toEqual(fromStr);
expect((this.context.component.value.to as Date).toISOString()).toEqual(toStr);
});

it('should automatically render a toggle button with a Forge text-field component', function(this: ITestContext) {
this.context = setupTestContext(false, false, false, false);

Expand Down

0 comments on commit 58282b1

Please sign in to comment.