fix(datetime): switching month and year accounts for day (#25996)

resolves #25585
This commit is contained in:
Liam DeBeasi
2022-09-23 08:31:39 -05:00
committed by GitHub
parent 23470f6429
commit 11f44e94f4
3 changed files with 90 additions and 4 deletions

View File

@ -45,6 +45,7 @@ import {
getPreviousWeek, getPreviousWeek,
getPreviousYear, getPreviousYear,
getStartOfWeek, getStartOfWeek,
validateParts,
} from './utils/manipulation'; } from './utils/manipulation';
import { import {
clampDate, clampDate,
@ -583,6 +584,19 @@ export class Datetime implements ComponentInterface {
private setActiveParts = (parts: DatetimeParts, removeDate = false) => { private setActiveParts = (parts: DatetimeParts, removeDate = false) => {
const { multiple, activePartsClone, highlightActiveParts } = this; const { multiple, activePartsClone, highlightActiveParts } = this;
/**
* When setting the active parts, it is possible
* to set invalid data. For example,
* when updating January 31 to February,
* February 31 does not exist. As a result
* we need to validate the active parts and
* ensure that we are only setting valid dates.
* Additionally, we need to update the working parts
* too in the event that the validated parts are different.
*/
const validatedParts = validateParts(parts);
this.setWorkingParts(validatedParts);
if (multiple) { if (multiple) {
/** /**
* We read from activePartsClone here because valueChanged() only updates that, * We read from activePartsClone here because valueChanged() only updates that,
@ -595,20 +609,20 @@ export class Datetime implements ComponentInterface {
*/ */
const activePartsArray = Array.isArray(activePartsClone) ? activePartsClone : [activePartsClone]; const activePartsArray = Array.isArray(activePartsClone) ? activePartsClone : [activePartsClone];
if (removeDate) { if (removeDate) {
this.activeParts = activePartsArray.filter((p) => !isSameDay(p, parts)); this.activeParts = activePartsArray.filter((p) => !isSameDay(p, validatedParts));
} else if (highlightActiveParts) { } else if (highlightActiveParts) {
this.activeParts = [...activePartsArray, parts]; this.activeParts = [...activePartsArray, validatedParts];
} else { } else {
/** /**
* If highlightActiveParts is false, that means we just have a * If highlightActiveParts is false, that means we just have a
* default value of today in activeParts; we need to replace that * default value of today in activeParts; we need to replace that
* rather than adding to it since it's just a placeholder. * rather than adding to it since it's just a placeholder.
*/ */
this.activeParts = [parts]; this.activeParts = [validatedParts];
} }
} else { } else {
this.activeParts = { this.activeParts = {
...parts, ...validatedParts,
}; };
} }

View File

@ -0,0 +1,48 @@
import { expect } from '@playwright/test';
import { test } from '@utils/test/playwright';
test.describe('datetime: switching months with different number of days', () => {
test.beforeEach(async ({ page, skip }) => {
skip.rtl();
skip.mode('ios');
await page.setContent(`
<ion-datetime locale="en-US" presentation="date" value="2022-01-31"></ion-datetime>
`);
await page.waitForSelector('.datetime-ready');
});
test('should switch the calendar header when moving to a month with a different number of days', async ({ page }) => {
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
await expect(monthYearToggle).toContainText('January 2022');
await monthYearToggle.click();
await page.waitForChanges();
// February
await monthColumnItems.nth(1).click();
await page.waitForChanges();
await expect(monthYearToggle).toContainText('February 2022');
});
test('should adjust the selected day when moving to a month with a different number of days', async ({ page }) => {
const monthYearToggle = page.locator('ion-datetime .calendar-month-year');
const monthColumnItems = page.locator('ion-datetime .month-column .picker-item:not(.picker-item-empty)');
const datetime = page.locator('ion-datetime');
const ionChange = await page.spyOnEvent('ionChange');
await monthYearToggle.click();
await page.waitForChanges();
// February
await monthColumnItems.nth(1).click();
await ionChange.next();
await expect(ionChange).toHaveReceivedEventTimes(1);
await expect(datetime).toHaveJSProperty('value', '2022-02-28');
});
});

View File

@ -339,3 +339,27 @@ export const calculateHourFromAMPM = (currentParts: DatetimeParts, newAMPM: 'am'
return newHour; return newHour;
}; };
/**
* Updates parts to ensure that month and day
* values are valid. For days that do not exist,
* the closest valid day is used.
*/
export const validateParts = (parts: DatetimeParts): DatetimeParts => {
const { month, day, year } = parts;
const partsCopy = { ...parts };
const numDays = getNumDaysInMonth(month, year);
/**
* If the max number of days
* is greater than the day we want
* to set, update the DatetimeParts
* day field to be the max days.
*/
if (day !== null && numDays < day) {
partsCopy.day = numDays;
}
return partsCopy;
};