@khanacademy/wonder-blocks-birthday-picker 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-birthday-picker
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5536d12e: Add `monthYearOnly` prop to hide the `day` field from the UI. Passes the first day of the selected month for this case.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- @khanacademy/wonder-blocks-dropdown@2.6.5
|
|
12
|
+
|
|
3
13
|
## 1.1.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/dist/es/index.js
CHANGED
|
@@ -18,7 +18,12 @@ const defaultLabels = Object.freeze({
|
|
|
18
18
|
month: "Month",
|
|
19
19
|
year: "Year",
|
|
20
20
|
day: "Day"
|
|
21
|
-
});
|
|
21
|
+
}); // Default minWidth value when we include the full DOB.
|
|
22
|
+
|
|
23
|
+
const FIELD_MIN_WIDTH_FULL = 110; // Alternative minWidth value when we hide the day field.
|
|
24
|
+
// See: https://www.figma.com/file/uJZi9ZvuEz5N8GJ3HqKFAa/(2021)-Account-records?node-id=20%3A398
|
|
25
|
+
|
|
26
|
+
const FIELD_MIN_WIDTH_MONTH_YEAR = 167;
|
|
22
27
|
/**
|
|
23
28
|
* Birthday Picker. Similar to a datepicker, but specifically for birthdates.
|
|
24
29
|
* We don't want to show a calendar in this case as it can be quite tedious to
|
|
@@ -127,11 +132,12 @@ class BirthdayPicker extends React.Component {
|
|
|
127
132
|
|
|
128
133
|
getStateFromDefault() {
|
|
129
134
|
const {
|
|
130
|
-
defaultValue
|
|
135
|
+
defaultValue,
|
|
136
|
+
monthYearOnly
|
|
131
137
|
} = this.props;
|
|
132
138
|
const initialState = {
|
|
133
139
|
month: null,
|
|
134
|
-
day: null,
|
|
140
|
+
day: monthYearOnly ? "1" : null,
|
|
135
141
|
year: null,
|
|
136
142
|
error: null
|
|
137
143
|
}; // merge custom labels with the default ones
|
|
@@ -191,34 +197,45 @@ class BirthdayPicker extends React.Component {
|
|
|
191
197
|
}, error)));
|
|
192
198
|
}
|
|
193
199
|
|
|
194
|
-
|
|
200
|
+
renderMonth() {
|
|
195
201
|
const {
|
|
196
|
-
disabled
|
|
202
|
+
disabled,
|
|
203
|
+
monthYearOnly
|
|
197
204
|
} = this.props;
|
|
198
205
|
const {
|
|
199
|
-
month
|
|
200
|
-
day,
|
|
201
|
-
year
|
|
206
|
+
month
|
|
202
207
|
} = this.state;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
style: {
|
|
206
|
-
flexDirection: "row"
|
|
207
|
-
}
|
|
208
|
-
}, /*#__PURE__*/React.createElement(SingleSelect, {
|
|
208
|
+
const minWidth = monthYearOnly ? FIELD_MIN_WIDTH_MONTH_YEAR : FIELD_MIN_WIDTH_FULL;
|
|
209
|
+
return /*#__PURE__*/React.createElement(SingleSelect, {
|
|
209
210
|
disabled: disabled,
|
|
210
211
|
placeholder: this.labels.month,
|
|
211
212
|
onChange: this.handleMonthChange,
|
|
212
213
|
selectedValue: month,
|
|
213
214
|
style: {
|
|
214
|
-
minWidth
|
|
215
|
+
minWidth
|
|
215
216
|
},
|
|
216
217
|
testId: "birthday-picker-month"
|
|
217
218
|
}, moment.monthsShort().map((month, i) => /*#__PURE__*/React.createElement(OptionItem, {
|
|
218
219
|
key: month,
|
|
219
220
|
label: month,
|
|
220
221
|
value: String(i)
|
|
221
|
-
})))
|
|
222
|
+
})));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
maybeRenderDay() {
|
|
226
|
+
const {
|
|
227
|
+
disabled,
|
|
228
|
+
monthYearOnly
|
|
229
|
+
} = this.props;
|
|
230
|
+
const {
|
|
231
|
+
day
|
|
232
|
+
} = this.state; // Hide the day field if the month/year only mode is enabled.
|
|
233
|
+
|
|
234
|
+
if (monthYearOnly) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Strut, {
|
|
222
239
|
size: Spacing.xSmall_8
|
|
223
240
|
}), /*#__PURE__*/React.createElement(SingleSelect, {
|
|
224
241
|
disabled: disabled,
|
|
@@ -233,22 +250,43 @@ class BirthdayPicker extends React.Component {
|
|
|
233
250
|
key: String(day + 1),
|
|
234
251
|
label: String(day + 1),
|
|
235
252
|
value: String(day + 1)
|
|
236
|
-
})))
|
|
237
|
-
|
|
238
|
-
|
|
253
|
+
}))));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
renderYear() {
|
|
257
|
+
const {
|
|
258
|
+
disabled,
|
|
259
|
+
monthYearOnly
|
|
260
|
+
} = this.props;
|
|
261
|
+
const {
|
|
262
|
+
year
|
|
263
|
+
} = this.state;
|
|
264
|
+
const minWidth = monthYearOnly ? FIELD_MIN_WIDTH_MONTH_YEAR : FIELD_MIN_WIDTH_FULL;
|
|
265
|
+
return /*#__PURE__*/React.createElement(SingleSelect, {
|
|
239
266
|
disabled: disabled,
|
|
240
267
|
placeholder: this.labels.year,
|
|
241
268
|
onChange: this.handleYearChange,
|
|
242
269
|
selectedValue: year,
|
|
243
270
|
style: {
|
|
244
|
-
minWidth
|
|
271
|
+
minWidth
|
|
245
272
|
},
|
|
246
273
|
testId: "birthday-picker-year"
|
|
247
274
|
}, Array.from(Array(120)).map((_, yearOffset) => /*#__PURE__*/React.createElement(OptionItem, {
|
|
248
275
|
key: String(CUR_YEAR - yearOffset),
|
|
249
276
|
label: String(CUR_YEAR - yearOffset),
|
|
250
277
|
value: String(CUR_YEAR - yearOffset)
|
|
251
|
-
})))
|
|
278
|
+
})));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
render() {
|
|
282
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
|
|
283
|
+
testId: "birthday-picker",
|
|
284
|
+
style: {
|
|
285
|
+
flexDirection: "row"
|
|
286
|
+
}
|
|
287
|
+
}, this.renderMonth(), this.maybeRenderDay(), /*#__PURE__*/React.createElement(Strut, {
|
|
288
|
+
size: Spacing.xSmall_8
|
|
289
|
+
}), this.renderYear()), this.maybeRenderError());
|
|
252
290
|
}
|
|
253
291
|
|
|
254
292
|
}
|
package/dist/index.js
CHANGED
|
@@ -176,7 +176,12 @@ const defaultLabels = Object.freeze({
|
|
|
176
176
|
month: "Month",
|
|
177
177
|
year: "Year",
|
|
178
178
|
day: "Day"
|
|
179
|
-
});
|
|
179
|
+
}); // Default minWidth value when we include the full DOB.
|
|
180
|
+
|
|
181
|
+
const FIELD_MIN_WIDTH_FULL = 110; // Alternative minWidth value when we hide the day field.
|
|
182
|
+
// See: https://www.figma.com/file/uJZi9ZvuEz5N8GJ3HqKFAa/(2021)-Account-records?node-id=20%3A398
|
|
183
|
+
|
|
184
|
+
const FIELD_MIN_WIDTH_MONTH_YEAR = 167;
|
|
180
185
|
/**
|
|
181
186
|
* Birthday Picker. Similar to a datepicker, but specifically for birthdates.
|
|
182
187
|
* We don't want to show a calendar in this case as it can be quite tedious to
|
|
@@ -285,11 +290,12 @@ class BirthdayPicker extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
|
|
|
285
290
|
|
|
286
291
|
getStateFromDefault() {
|
|
287
292
|
const {
|
|
288
|
-
defaultValue
|
|
293
|
+
defaultValue,
|
|
294
|
+
monthYearOnly
|
|
289
295
|
} = this.props;
|
|
290
296
|
const initialState = {
|
|
291
297
|
month: null,
|
|
292
|
-
day: null,
|
|
298
|
+
day: monthYearOnly ? "1" : null,
|
|
293
299
|
year: null,
|
|
294
300
|
error: null
|
|
295
301
|
}; // merge custom labels with the default ones
|
|
@@ -351,34 +357,45 @@ class BirthdayPicker extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
|
|
|
351
357
|
}, error)));
|
|
352
358
|
}
|
|
353
359
|
|
|
354
|
-
|
|
360
|
+
renderMonth() {
|
|
355
361
|
const {
|
|
356
|
-
disabled
|
|
362
|
+
disabled,
|
|
363
|
+
monthYearOnly
|
|
357
364
|
} = this.props;
|
|
358
365
|
const {
|
|
359
|
-
month
|
|
360
|
-
day,
|
|
361
|
-
year
|
|
366
|
+
month
|
|
362
367
|
} = this.state;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
style: {
|
|
366
|
-
flexDirection: "row"
|
|
367
|
-
}
|
|
368
|
-
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_dropdown__WEBPACK_IMPORTED_MODULE_8__["SingleSelect"], {
|
|
368
|
+
const minWidth = monthYearOnly ? FIELD_MIN_WIDTH_MONTH_YEAR : FIELD_MIN_WIDTH_FULL;
|
|
369
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_dropdown__WEBPACK_IMPORTED_MODULE_8__["SingleSelect"], {
|
|
369
370
|
disabled: disabled,
|
|
370
371
|
placeholder: this.labels.month,
|
|
371
372
|
onChange: this.handleMonthChange,
|
|
372
373
|
selectedValue: month,
|
|
373
374
|
style: {
|
|
374
|
-
minWidth
|
|
375
|
+
minWidth
|
|
375
376
|
},
|
|
376
377
|
testId: "birthday-picker-month"
|
|
377
378
|
}, moment__WEBPACK_IMPORTED_MODULE_0___default.a.monthsShort().map((month, i) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_dropdown__WEBPACK_IMPORTED_MODULE_8__["OptionItem"], {
|
|
378
379
|
key: month,
|
|
379
380
|
label: month,
|
|
380
381
|
value: String(i)
|
|
381
|
-
})))
|
|
382
|
+
})));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
maybeRenderDay() {
|
|
386
|
+
const {
|
|
387
|
+
disabled,
|
|
388
|
+
monthYearOnly
|
|
389
|
+
} = this.props;
|
|
390
|
+
const {
|
|
391
|
+
day
|
|
392
|
+
} = this.state; // Hide the day field if the month/year only mode is enabled.
|
|
393
|
+
|
|
394
|
+
if (monthYearOnly) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__["Strut"], {
|
|
382
399
|
size: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8
|
|
383
400
|
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_dropdown__WEBPACK_IMPORTED_MODULE_8__["SingleSelect"], {
|
|
384
401
|
disabled: disabled,
|
|
@@ -393,22 +410,43 @@ class BirthdayPicker extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
|
|
|
393
410
|
key: String(day + 1),
|
|
394
411
|
label: String(day + 1),
|
|
395
412
|
value: String(day + 1)
|
|
396
|
-
})))
|
|
397
|
-
|
|
398
|
-
|
|
413
|
+
}))));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
renderYear() {
|
|
417
|
+
const {
|
|
418
|
+
disabled,
|
|
419
|
+
monthYearOnly
|
|
420
|
+
} = this.props;
|
|
421
|
+
const {
|
|
422
|
+
year
|
|
423
|
+
} = this.state;
|
|
424
|
+
const minWidth = monthYearOnly ? FIELD_MIN_WIDTH_MONTH_YEAR : FIELD_MIN_WIDTH_FULL;
|
|
425
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_dropdown__WEBPACK_IMPORTED_MODULE_8__["SingleSelect"], {
|
|
399
426
|
disabled: disabled,
|
|
400
427
|
placeholder: this.labels.year,
|
|
401
428
|
onChange: this.handleYearChange,
|
|
402
429
|
selectedValue: year,
|
|
403
430
|
style: {
|
|
404
|
-
minWidth
|
|
431
|
+
minWidth
|
|
405
432
|
},
|
|
406
433
|
testId: "birthday-picker-year"
|
|
407
434
|
}, Array.from(Array(120)).map((_, yearOffset) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_dropdown__WEBPACK_IMPORTED_MODULE_8__["OptionItem"], {
|
|
408
435
|
key: String(CUR_YEAR - yearOffset),
|
|
409
436
|
label: String(CUR_YEAR - yearOffset),
|
|
410
437
|
value: String(CUR_YEAR - yearOffset)
|
|
411
|
-
})))
|
|
438
|
+
})));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
render() {
|
|
442
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["View"], {
|
|
443
|
+
testId: "birthday-picker",
|
|
444
|
+
style: {
|
|
445
|
+
flexDirection: "row"
|
|
446
|
+
}
|
|
447
|
+
}, this.renderMonth(), this.maybeRenderDay(), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__["Strut"], {
|
|
448
|
+
size: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8
|
|
449
|
+
}), this.renderYear()), this.maybeRenderError());
|
|
412
450
|
}
|
|
413
451
|
|
|
414
452
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-birthday-picker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@babel/runtime": "^7.16.3",
|
|
17
17
|
"@khanacademy/wonder-blocks-color": "^1.1.20",
|
|
18
18
|
"@khanacademy/wonder-blocks-core": "^4.2.0",
|
|
19
|
-
"@khanacademy/wonder-blocks-dropdown": "^2.6.
|
|
19
|
+
"@khanacademy/wonder-blocks-dropdown": "^2.6.5",
|
|
20
20
|
"@khanacademy/wonder-blocks-icon": "^1.2.24",
|
|
21
21
|
"@khanacademy/wonder-blocks-layout": "^1.4.6",
|
|
22
22
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5",
|
|
@@ -119,3 +119,21 @@ DisabledBirthdayPicker.parameters = {
|
|
|
119
119
|
"A BirthdayPicker can be disabled by passing the `disabled` prop. This will disable all the dropdown controls and prevent them from being interacted with.",
|
|
120
120
|
},
|
|
121
121
|
};
|
|
122
|
+
|
|
123
|
+
export const BirthdayPickerWithYearAndMonthOnly: StoryComponentType =
|
|
124
|
+
Template.bind({});
|
|
125
|
+
|
|
126
|
+
BirthdayPickerWithYearAndMonthOnly.args = {
|
|
127
|
+
monthYearOnly: true,
|
|
128
|
+
onChange: (date: ?string) => {
|
|
129
|
+
// eslint-disable-next-line no-console
|
|
130
|
+
console.log("Date selected: ", date);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
BirthdayPickerWithYearAndMonthOnly.parameters = {
|
|
135
|
+
docs: {
|
|
136
|
+
storyDescription:
|
|
137
|
+
"A BirthdayPicker can be configured to only show the year and month dropdowns. This can be useful when we want to display and collect a birthday that doesn't require the full DOB for privacy reasons.",
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -34,6 +34,18 @@ describe("BirthdayPicker", () => {
|
|
|
34
34
|
expect(yearPicker).toHaveTextContent("Year");
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
+
it("renders without the day field if monthYearOnly is set", () => {
|
|
38
|
+
// Arrange
|
|
39
|
+
|
|
40
|
+
// Act
|
|
41
|
+
render(<BirthdayPicker monthYearOnly={true} onChange={() => {}} />);
|
|
42
|
+
|
|
43
|
+
const dayPicker = screen.queryByTestId("birthday-picker-day");
|
|
44
|
+
|
|
45
|
+
// Assert
|
|
46
|
+
expect(dayPicker).not.toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
|
|
37
49
|
it("renders with a valid default value", () => {
|
|
38
50
|
// Arrange
|
|
39
51
|
const date = moment(today);
|
|
@@ -169,9 +181,9 @@ describe("BirthdayPicker", () => {
|
|
|
169
181
|
// Arrange
|
|
170
182
|
const onChange = jest.fn();
|
|
171
183
|
|
|
172
|
-
// Act
|
|
173
184
|
render(<BirthdayPicker onChange={onChange} />);
|
|
174
185
|
|
|
186
|
+
// Act
|
|
175
187
|
userEvent.click(screen.getByTestId("birthday-picker-month"));
|
|
176
188
|
const monthOption = await screen.findByRole("option", {
|
|
177
189
|
name: "Jul",
|
|
@@ -258,7 +270,6 @@ describe("BirthdayPicker", () => {
|
|
|
258
270
|
// Arrange
|
|
259
271
|
const onChange = jest.fn();
|
|
260
272
|
|
|
261
|
-
// Act
|
|
262
273
|
render(
|
|
263
274
|
<BirthdayPicker
|
|
264
275
|
defaultValue="2017-07-17"
|
|
@@ -266,6 +277,7 @@ describe("BirthdayPicker", () => {
|
|
|
266
277
|
/>,
|
|
267
278
|
);
|
|
268
279
|
|
|
280
|
+
// Act
|
|
269
281
|
userEvent.click(screen.getByTestId("birthday-picker-month"));
|
|
270
282
|
const monthOption = await screen.findByRole("option", {
|
|
271
283
|
name: "Aug",
|
|
@@ -327,7 +339,6 @@ describe("BirthdayPicker", () => {
|
|
|
327
339
|
// Arrange
|
|
328
340
|
const onChange = jest.fn();
|
|
329
341
|
|
|
330
|
-
// Act
|
|
331
342
|
render(
|
|
332
343
|
<BirthdayPicker
|
|
333
344
|
defaultValue="2021-02-31"
|
|
@@ -335,6 +346,7 @@ describe("BirthdayPicker", () => {
|
|
|
335
346
|
/>,
|
|
336
347
|
);
|
|
337
348
|
|
|
349
|
+
// Act
|
|
338
350
|
userEvent.click(screen.getByTestId("birthday-picker-year"));
|
|
339
351
|
const yearOption = await screen.findByRole("option", {
|
|
340
352
|
name: "2020",
|
|
@@ -346,6 +358,68 @@ describe("BirthdayPicker", () => {
|
|
|
346
358
|
// Assert
|
|
347
359
|
expect(onChange).toHaveBeenCalledTimes(1);
|
|
348
360
|
});
|
|
361
|
+
|
|
362
|
+
it("onChange triggers the first day of the month when monthYearOnly is set", async () => {
|
|
363
|
+
// Arrange
|
|
364
|
+
const onChange = jest.fn();
|
|
365
|
+
|
|
366
|
+
render(<BirthdayPicker monthYearOnly={true} onChange={onChange} />);
|
|
367
|
+
|
|
368
|
+
// Act
|
|
369
|
+
userEvent.click(screen.getByTestId("birthday-picker-month"));
|
|
370
|
+
const monthOption = await screen.findByRole("option", {
|
|
371
|
+
name: "Aug",
|
|
372
|
+
});
|
|
373
|
+
userEvent.click(monthOption, undefined, {
|
|
374
|
+
skipPointerEventsCheck: true,
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
userEvent.click(screen.getByTestId("birthday-picker-year"));
|
|
378
|
+
const yearOption = await screen.findByRole("option", {
|
|
379
|
+
name: "2018",
|
|
380
|
+
});
|
|
381
|
+
userEvent.click(yearOption, undefined, {
|
|
382
|
+
skipPointerEventsCheck: true,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Assert
|
|
386
|
+
// Verify that we passed the first day of the month
|
|
387
|
+
expect(onChange).toHaveBeenCalledWith("2018-08-01");
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("onChange triggers the passed-in day intact when defaultValue and monthYearOnly are set", async () => {
|
|
391
|
+
// Arrange
|
|
392
|
+
const onChange = jest.fn();
|
|
393
|
+
|
|
394
|
+
render(
|
|
395
|
+
<BirthdayPicker
|
|
396
|
+
defaultValue="2017-07-17"
|
|
397
|
+
monthYearOnly={true}
|
|
398
|
+
onChange={onChange}
|
|
399
|
+
/>,
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// Act
|
|
403
|
+
userEvent.click(screen.getByTestId("birthday-picker-month"));
|
|
404
|
+
const monthOption = await screen.findByRole("option", {
|
|
405
|
+
name: "Aug",
|
|
406
|
+
});
|
|
407
|
+
userEvent.click(monthOption, undefined, {
|
|
408
|
+
skipPointerEventsCheck: true,
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
userEvent.click(screen.getByTestId("birthday-picker-year"));
|
|
412
|
+
const yearOption = await screen.findByRole("option", {
|
|
413
|
+
name: "2018",
|
|
414
|
+
});
|
|
415
|
+
userEvent.click(yearOption, undefined, {
|
|
416
|
+
skipPointerEventsCheck: true,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Assert
|
|
420
|
+
// Verify that we passed the same day originally passed in.
|
|
421
|
+
expect(onChange).toHaveBeenCalledWith("2018-08-17");
|
|
422
|
+
});
|
|
349
423
|
});
|
|
350
424
|
|
|
351
425
|
describe("labels", () => {
|
|
@@ -49,6 +49,16 @@ type Props = {|
|
|
|
49
49
|
*/
|
|
50
50
|
labels?: Labels,
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Whether we want to hide the day field.
|
|
54
|
+
*
|
|
55
|
+
* **NOTE:** We will set the day to the _first_ day of the _selected_ month
|
|
56
|
+
* if the day field is hidden. Please make sure to modify the passed date
|
|
57
|
+
* value to fit different needs (e.g. if you want to set the _first_ day of
|
|
58
|
+
* the _following_ month instead).
|
|
59
|
+
*/
|
|
60
|
+
monthYearOnly?: boolean,
|
|
61
|
+
|
|
52
62
|
/**
|
|
53
63
|
* Listen for changes to the birthdate. Could be a string in the YYYY-MM-DD
|
|
54
64
|
* format or `null`.
|
|
@@ -87,6 +97,13 @@ export const defaultLabels: Labels = Object.freeze({
|
|
|
87
97
|
day: "Day",
|
|
88
98
|
});
|
|
89
99
|
|
|
100
|
+
// Default minWidth value when we include the full DOB.
|
|
101
|
+
const FIELD_MIN_WIDTH_FULL = 110;
|
|
102
|
+
|
|
103
|
+
// Alternative minWidth value when we hide the day field.
|
|
104
|
+
// See: https://www.figma.com/file/uJZi9ZvuEz5N8GJ3HqKFAa/(2021)-Account-records?node-id=20%3A398
|
|
105
|
+
const FIELD_MIN_WIDTH_MONTH_YEAR = 167;
|
|
106
|
+
|
|
90
107
|
/**
|
|
91
108
|
* Birthday Picker. Similar to a datepicker, but specifically for birthdates.
|
|
92
109
|
* We don't want to show a calendar in this case as it can be quite tedious to
|
|
@@ -134,10 +151,10 @@ export default class BirthdayPicker extends React.Component<Props, State> {
|
|
|
134
151
|
* Calculates the initial state values based on the default value.
|
|
135
152
|
*/
|
|
136
153
|
getStateFromDefault(): State {
|
|
137
|
-
const {defaultValue} = this.props;
|
|
154
|
+
const {defaultValue, monthYearOnly} = this.props;
|
|
138
155
|
const initialState: State = {
|
|
139
156
|
month: null,
|
|
140
|
-
day: null,
|
|
157
|
+
day: monthYearOnly ? "1" : null,
|
|
141
158
|
year: null,
|
|
142
159
|
error: null,
|
|
143
160
|
};
|
|
@@ -252,63 +269,99 @@ export default class BirthdayPicker extends React.Component<Props, State> {
|
|
|
252
269
|
);
|
|
253
270
|
}
|
|
254
271
|
|
|
255
|
-
|
|
256
|
-
const {disabled} = this.props;
|
|
257
|
-
const {month
|
|
272
|
+
renderMonth(): React.Node {
|
|
273
|
+
const {disabled, monthYearOnly} = this.props;
|
|
274
|
+
const {month} = this.state;
|
|
275
|
+
const minWidth = monthYearOnly
|
|
276
|
+
? FIELD_MIN_WIDTH_MONTH_YEAR
|
|
277
|
+
: FIELD_MIN_WIDTH_FULL;
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<SingleSelect
|
|
281
|
+
disabled={disabled}
|
|
282
|
+
placeholder={this.labels.month}
|
|
283
|
+
onChange={this.handleMonthChange}
|
|
284
|
+
selectedValue={month}
|
|
285
|
+
style={{minWidth}}
|
|
286
|
+
testId="birthday-picker-month"
|
|
287
|
+
>
|
|
288
|
+
{moment.monthsShort().map((month, i) => (
|
|
289
|
+
<OptionItem key={month} label={month} value={String(i)} />
|
|
290
|
+
))}
|
|
291
|
+
</SingleSelect>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
maybeRenderDay(): ?React.Node {
|
|
296
|
+
const {disabled, monthYearOnly} = this.props;
|
|
297
|
+
const {day} = this.state;
|
|
298
|
+
|
|
299
|
+
// Hide the day field if the month/year only mode is enabled.
|
|
300
|
+
if (monthYearOnly) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
258
303
|
|
|
304
|
+
return (
|
|
305
|
+
<>
|
|
306
|
+
<Strut size={Spacing.xSmall_8} />
|
|
307
|
+
<SingleSelect
|
|
308
|
+
disabled={disabled}
|
|
309
|
+
placeholder={this.labels.day}
|
|
310
|
+
onChange={this.handleDayChange}
|
|
311
|
+
selectedValue={day}
|
|
312
|
+
style={{minWidth: 100}}
|
|
313
|
+
testId="birthday-picker-day"
|
|
314
|
+
>
|
|
315
|
+
{Array.from(Array(31)).map((_, day) => (
|
|
316
|
+
<OptionItem
|
|
317
|
+
key={String(day + 1)}
|
|
318
|
+
label={String(day + 1)}
|
|
319
|
+
value={String(day + 1)}
|
|
320
|
+
/>
|
|
321
|
+
))}
|
|
322
|
+
</SingleSelect>
|
|
323
|
+
</>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
renderYear(): React.Node {
|
|
328
|
+
const {disabled, monthYearOnly} = this.props;
|
|
329
|
+
const {year} = this.state;
|
|
330
|
+
const minWidth = monthYearOnly
|
|
331
|
+
? FIELD_MIN_WIDTH_MONTH_YEAR
|
|
332
|
+
: FIELD_MIN_WIDTH_FULL;
|
|
333
|
+
|
|
334
|
+
return (
|
|
335
|
+
<SingleSelect
|
|
336
|
+
disabled={disabled}
|
|
337
|
+
placeholder={this.labels.year}
|
|
338
|
+
onChange={this.handleYearChange}
|
|
339
|
+
selectedValue={year}
|
|
340
|
+
style={{minWidth}}
|
|
341
|
+
testId="birthday-picker-year"
|
|
342
|
+
>
|
|
343
|
+
{Array.from(Array(120)).map((_, yearOffset) => (
|
|
344
|
+
<OptionItem
|
|
345
|
+
key={String(CUR_YEAR - yearOffset)}
|
|
346
|
+
label={String(CUR_YEAR - yearOffset)}
|
|
347
|
+
value={String(CUR_YEAR - yearOffset)}
|
|
348
|
+
/>
|
|
349
|
+
))}
|
|
350
|
+
</SingleSelect>
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
render(): React.Element<any> {
|
|
259
355
|
return (
|
|
260
356
|
<>
|
|
261
357
|
<View testId="birthday-picker" style={{flexDirection: "row"}}>
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
selectedValue={month}
|
|
267
|
-
style={{minWidth: 110}}
|
|
268
|
-
testId="birthday-picker-month"
|
|
269
|
-
>
|
|
270
|
-
{moment.monthsShort().map((month, i) => (
|
|
271
|
-
<OptionItem
|
|
272
|
-
key={month}
|
|
273
|
-
label={month}
|
|
274
|
-
value={String(i)}
|
|
275
|
-
/>
|
|
276
|
-
))}
|
|
277
|
-
</SingleSelect>
|
|
278
|
-
<Strut size={Spacing.xSmall_8} />
|
|
279
|
-
<SingleSelect
|
|
280
|
-
disabled={disabled}
|
|
281
|
-
placeholder={this.labels.day}
|
|
282
|
-
onChange={this.handleDayChange}
|
|
283
|
-
selectedValue={day}
|
|
284
|
-
style={{minWidth: 100}}
|
|
285
|
-
testId="birthday-picker-day"
|
|
286
|
-
>
|
|
287
|
-
{Array.from(Array(31)).map((_, day) => (
|
|
288
|
-
<OptionItem
|
|
289
|
-
key={String(day + 1)}
|
|
290
|
-
label={String(day + 1)}
|
|
291
|
-
value={String(day + 1)}
|
|
292
|
-
/>
|
|
293
|
-
))}
|
|
294
|
-
</SingleSelect>
|
|
358
|
+
{this.renderMonth()}
|
|
359
|
+
|
|
360
|
+
{this.maybeRenderDay()}
|
|
361
|
+
|
|
295
362
|
<Strut size={Spacing.xSmall_8} />
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
placeholder={this.labels.year}
|
|
299
|
-
onChange={this.handleYearChange}
|
|
300
|
-
selectedValue={year}
|
|
301
|
-
style={{minWidth: 110}}
|
|
302
|
-
testId="birthday-picker-year"
|
|
303
|
-
>
|
|
304
|
-
{Array.from(Array(120)).map((_, yearOffset) => (
|
|
305
|
-
<OptionItem
|
|
306
|
-
key={String(CUR_YEAR - yearOffset)}
|
|
307
|
-
label={String(CUR_YEAR - yearOffset)}
|
|
308
|
-
value={String(CUR_YEAR - yearOffset)}
|
|
309
|
-
/>
|
|
310
|
-
))}
|
|
311
|
-
</SingleSelect>
|
|
363
|
+
|
|
364
|
+
{this.renderYear()}
|
|
312
365
|
</View>
|
|
313
366
|
{this.maybeRenderError()}
|
|
314
367
|
</>
|