Skip to content

Commit 64e4927

Browse files
authored
Update monthYearOnly to use last day of month (#2486)
## Summary: BirthdayPicker currently use the first day of the month for the date if `monthYearOnly` prop is set to `true`. But for most use-cases developers want to use the last day of the month so that a user who is still 17, for example, is not considered 18, if their birthday is anything after the 1st of the month. This update modifies the behavior of the component to pass the last day of the month to `onChange` if `monthYearOnly` is set to `true`. Issue: PG-5959 ## Test plan: - Modified unit tests to prove last day of month is returned when the prop is set
2 parents 8f53293 + 3903661 commit 64e4927

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

.changeset/unlucky-cups-notice.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@khanacademy/wonder-blocks-birthday-picker": minor
3+
---
4+
5+
Added useLastOfMonth to BirthdayPicker props

packages/wonder-blocks-birthday-picker/src/components/__tests__/birthday-picker.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ describe("BirthdayPicker", () => {
435435
expect(onChange).toHaveBeenCalledTimes(1);
436436
});
437437

438-
it("onChange triggers the first day of the month when monthYearOnly is set", async () => {
438+
it("onChange triggers the last day of the month when monthYearOnly is set", async () => {
439439
// Arrange
440440
const onChange = jest.fn();
441441

@@ -460,10 +460,10 @@ describe("BirthdayPicker", () => {
460460

461461
// Assert
462462
// Verify that we passed the first day of the month
463-
expect(onChange).toHaveBeenCalledWith("2018-08-01");
463+
expect(onChange).toHaveBeenCalledWith("2018-08-31");
464464
});
465465

466-
it("onChange triggers the passed-in day intact when defaultValue and monthYearOnly are set", async () => {
466+
it("onChange triggers uses last of month when defaultValue and monthYearOnly are set", async () => {
467467
// Arrange
468468
const onChange = jest.fn();
469469

@@ -494,7 +494,7 @@ describe("BirthdayPicker", () => {
494494

495495
// Assert
496496
// Verify that we passed the same day originally passed in.
497-
expect(onChange).toHaveBeenCalledWith("2018-08-17");
497+
expect(onChange).toHaveBeenCalledWith("2018-08-31");
498498
});
499499
});
500500

packages/wonder-blocks-birthday-picker/src/components/birthday-picker.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ type Props = {
4646
/**
4747
* Whether we want to hide the day field.
4848
*
49-
* **NOTE:** We will set the day to the _first_ day of the _selected_ month
49+
* **NOTE:** We will set the day to the _last_ day of the _selected_ month
5050
* if the day field is hidden. Please make sure to modify the passed date
51-
* value to fit different needs (e.g. if you want to set the _first_ day of
51+
* value to fit different needs (e.g. if you want to set the _last_ day of
5252
* the _following_ month instead).
5353
*/
5454
monthYearOnly?: boolean;
@@ -178,7 +178,7 @@ export default class BirthdayPicker extends React.Component<Props, State> {
178178
const {defaultValue, monthYearOnly} = this.props;
179179
const initialState: State = {
180180
month: null,
181-
day: monthYearOnly ? "1" : null,
181+
day: null,
182182
year: null,
183183
error: null,
184184
};
@@ -189,9 +189,13 @@ export default class BirthdayPicker extends React.Component<Props, State> {
189189
// If a default value was provided then we use moment to convert it
190190
// into a date that we can use to populate the
191191
if (defaultValue) {
192-
const date = moment(defaultValue);
192+
let date = moment(defaultValue);
193193

194194
if (date.isValid()) {
195+
if (monthYearOnly) {
196+
date = date.endOf("month");
197+
}
198+
195199
initialState.month = String(date.month());
196200
initialState.day = String(date.date());
197201
initialState.year = String(date.year());
@@ -230,17 +234,28 @@ export default class BirthdayPicker extends React.Component<Props, State> {
230234
*/
231235
handleChange: () => void = (): void => {
232236
const {month, day, year} = this.state;
237+
const {monthYearOnly} = this.props;
238+
239+
const dateFields = [year, month];
240+
if (!monthYearOnly) {
241+
dateFields.push(day);
242+
}
233243

234244
// If any of the values haven't been set then our overall value is
235245
// equal to null
236-
if (month === null || day === null || year === null) {
246+
if (dateFields.some((field) => field === null)) {
237247
this.reportChange(null);
238248
return;
239249
}
240250

241-
// This is a legal call to Moment, but our Moment types don't
242-
// recognize it.
243-
const date = moment([year, month, day]);
251+
// If the month/year only mode is enabled, we set the day to the
252+
// last day of the selected month.
253+
// NOTE: at this point dateFields is guaranteed to have non-null values
254+
// because of the .some() check above.
255+
let date = moment(dateFields as Array<string>);
256+
if (monthYearOnly) {
257+
date = date.endOf("month");
258+
}
244259

245260
// If the date is in the future or is invalid then we want to show
246261
// an error to the user and return a null value.

0 commit comments

Comments
 (0)