@dhis2-ui/calendar 10.0.0-alpha.5 → 10.0.0-alpha.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,21 @@
1
1
  "use strict";
2
2
 
3
+ var _button = require("@dhis2-ui/button");
3
4
  var _react = require("@testing-library/react");
4
- var _react2 = _interopRequireDefault(require("react"));
5
+ var _userEvent = _interopRequireDefault(require("@testing-library/user-event"));
6
+ var _react2 = _interopRequireWildcard(require("react"));
7
+ var _reactFinalForm = require("react-final-form");
5
8
  var _calendarInput = require("../calendar-input.js");
9
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
10
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
6
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
7
13
  describe('Calendar Input', () => {
14
+ beforeEach(() => {
15
+ jest.useFakeTimers();
16
+ jest.setSystemTime(new Date('2024-10-22T09:05:00.000Z'));
17
+ });
18
+ afterEach(jest.useRealTimers);
8
19
  it('allow selection of a date through the calendar widget', async () => {
9
20
  const onDateSelectMock = jest.fn();
10
21
  const screen = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(_calendarInput.CalendarInput, {
@@ -15,7 +26,7 @@ describe('Calendar Input', () => {
15
26
  _react.fireEvent.focus(dateInput);
16
27
  const calendar = await screen.findByTestId('calendar');
17
28
  expect(calendar).toBeInTheDocument();
18
- const todayString = new Date().toISOString().slice(0, -14);
29
+ const todayString = '2024-10-22';
19
30
  const today = (0, _react.within)(calendar).getByTestId(todayString);
20
31
  _react.fireEvent.click(today);
21
32
  await (0, _react.waitFor)(() => {
@@ -43,4 +54,210 @@ describe('Calendar Input', () => {
43
54
  calendarDateString: dateInputString
44
55
  }));
45
56
  });
46
- });
57
+ describe('validation', () => {
58
+ it('should validate minimum date', async () => {
59
+ const onDateSelectMock = jest.fn();
60
+ const screen = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
61
+ calendar: "gregory",
62
+ minDate: "2024-01-01",
63
+ onDateSelect: onDateSelectMock
64
+ }));
65
+ const dateInputString = '2023-10-12';
66
+ const dateInput = (0, _react.within)(screen.getByTestId('dhis2-uicore-input')).getByRole('textbox');
67
+ _userEvent.default.clear(dateInput);
68
+ _userEvent.default.type(dateInput, dateInputString);
69
+ _userEvent.default.tab();
70
+ expect(await screen.findByText('Date 2023-10-12 is less than the minimum allowed date 2024-01-01.'));
71
+ expect(onDateSelectMock).toHaveBeenCalledTimes(1);
72
+ });
73
+ it('should validate maximum date', async () => {
74
+ const {
75
+ getByTestId,
76
+ findByText
77
+ } = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
78
+ calendar: "gregory",
79
+ maxDate: "2024-01-01"
80
+ }));
81
+ const dateInputString = '2024-10-12';
82
+ const dateInput = (0, _react.within)(getByTestId('dhis2-uicore-input')).getByRole('textbox');
83
+ _userEvent.default.clear(dateInput);
84
+ _userEvent.default.type(dateInput, dateInputString);
85
+ _userEvent.default.tab();
86
+ expect(await findByText('Date 2024-10-12 is greater than the maximum allowed date 2024-01-01.'));
87
+ });
88
+ it('should validate date in ethiopic calendar', async () => {
89
+ const onDateSelectMock = jest.fn();
90
+ const {
91
+ getByTestId,
92
+ findByText,
93
+ queryByText
94
+ } = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
95
+ calendar: "ethiopian",
96
+ minDate: "2018-13-04",
97
+ onDateSelect: onDateSelectMock
98
+ }));
99
+ let dateInputString = '2018-13-02';
100
+ const dateInput = (0, _react.within)(getByTestId('dhis2-uicore-input')).getByRole('textbox');
101
+ _userEvent.default.clear(dateInput);
102
+ _userEvent.default.type(dateInput, dateInputString);
103
+ _userEvent.default.tab();
104
+ expect(await findByText('Date 2018-13-02 is less than the minimum allowed date 2018-13-04.'));
105
+ dateInputString = '2018-13-05';
106
+ _userEvent.default.clear(dateInput);
107
+ _userEvent.default.type(dateInput, dateInputString);
108
+ _userEvent.default.tab();
109
+ expect(queryByText('Date 2018-13-04 is less than the minimum allowed date 2018-13-05.')).not.toBeInTheDocument();
110
+ dateInputString = '2018-13-07';
111
+ _userEvent.default.clear(dateInput);
112
+ _userEvent.default.type(dateInput, dateInputString);
113
+ _userEvent.default.tab();
114
+ expect(await findByText('Invalid date in specified calendar')).toBeInTheDocument();
115
+ });
116
+ it('should validate date in nepali calendar', async () => {
117
+ const onDateSelectMock = jest.fn();
118
+ const {
119
+ getByTestId,
120
+ findByText,
121
+ queryByText
122
+ } = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
123
+ calendar: "nepali",
124
+ maxDate: "2080-05-30",
125
+ onDateSelect: onDateSelectMock
126
+ }));
127
+ let dateInputString = '2080-06-01';
128
+ const dateInput = (0, _react.within)(getByTestId('dhis2-uicore-input')).getByRole('textbox');
129
+ _userEvent.default.clear(dateInput);
130
+ _userEvent.default.type(dateInput, dateInputString);
131
+ _userEvent.default.tab();
132
+ expect(await findByText('Date 2080-06-01 is greater than the maximum allowed date 2080-05-30.'));
133
+ dateInputString = '2080-04-32';
134
+ _userEvent.default.clear(dateInput);
135
+ _userEvent.default.type(dateInput, dateInputString);
136
+ _userEvent.default.tab();
137
+ expect(queryByText(/greater than the maximum allowed date/)).not.toBeInTheDocument();
138
+ dateInputString = '2080-01-32';
139
+ _userEvent.default.clear(dateInput);
140
+ _userEvent.default.type(dateInput, dateInputString);
141
+ _userEvent.default.tab();
142
+ expect(await findByText('Invalid date in specified calendar')).toBeInTheDocument();
143
+ });
144
+ it('should validate from date picker', async () => {
145
+ const onDateSelectMock = jest.fn();
146
+ const {
147
+ queryByText,
148
+ getByText,
149
+ getByTestId
150
+ } = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
151
+ calendar: "gregory",
152
+ minDate: "2024-02-16",
153
+ onDateSelect: onDateSelectMock
154
+ }));
155
+ const dateInput = (0, _react.within)(getByTestId('dhis2-uicore-input')).getByRole('textbox');
156
+ await _userEvent.default.click(dateInput);
157
+ await _userEvent.default.click(getByText('17'));
158
+ expect(queryByText('17')).not.toBeInTheDocument();
159
+
160
+ // Bug where callback used to be called first with undefined
161
+ expect(onDateSelectMock).toHaveBeenCalledTimes(1);
162
+ expect(onDateSelectMock).toHaveBeenCalledWith({
163
+ calendarDateString: '2024-10-17',
164
+ validation: {
165
+ error: false,
166
+ valid: true,
167
+ warning: false
168
+ }
169
+ });
170
+ });
171
+ it('should validate with Clear', async () => {
172
+ const onDateSelectMock = jest.fn();
173
+ const {
174
+ queryByText,
175
+ getByText,
176
+ getByTestId
177
+ } = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
178
+ calendar: "gregory",
179
+ minDate: "2024-02-16",
180
+ onDateSelect: onDateSelectMock,
181
+ clearable: true
182
+ }));
183
+ const dateInputString = '2023-10-12';
184
+ const dateInput = (0, _react.within)(getByTestId('dhis2-uicore-input')).getByRole('textbox');
185
+ _userEvent.default.clear(dateInput);
186
+ _userEvent.default.type(dateInput, dateInputString);
187
+ _userEvent.default.tab();
188
+ expect(getByTestId('dhis2-uiwidgets-calendar-inputfield-validation')).toBeInTheDocument();
189
+ await _userEvent.default.click(getByText('Clear'));
190
+ expect(queryByText('17')).not.toBeInTheDocument();
191
+ expect(onDateSelectMock).toHaveBeenLastCalledWith({
192
+ calendarDateString: null,
193
+ validation: {
194
+ valid: true
195
+ }
196
+ });
197
+ });
198
+ it('should validate when Clearing manually (i.e. deleting text not using clear button)', async () => {
199
+ const onDateSelectMock = jest.fn();
200
+ const {
201
+ getByTestId
202
+ } = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(CalendarWithValidation, {
203
+ calendar: "gregory",
204
+ minDate: "2024-02-16",
205
+ onDateSelect: onDateSelectMock,
206
+ clearable: true
207
+ }));
208
+ const dateInputString = '2023-10-12';
209
+ const dateInput = (0, _react.within)(getByTestId('dhis2-uicore-input')).getByRole('textbox');
210
+ _userEvent.default.clear(dateInput);
211
+ _userEvent.default.type(dateInput, dateInputString);
212
+ _userEvent.default.tab();
213
+ expect(getByTestId('dhis2-uiwidgets-calendar-inputfield-validation')).toBeInTheDocument();
214
+ _userEvent.default.clear(dateInput);
215
+ _userEvent.default.tab();
216
+ expect(onDateSelectMock).toHaveBeenCalledWith({
217
+ calendarDateString: null,
218
+ validation: {
219
+ valid: true
220
+ }
221
+ });
222
+ });
223
+ });
224
+ });
225
+ const CalendarWithValidation = propsFromParent => {
226
+ const [date, setDate] = (0, _react2.useState)();
227
+ const [validation, setValidation] = (0, _react2.useState)({});
228
+ const errored = () => {
229
+ if (validation !== null && validation !== void 0 && validation.error) {
230
+ return {
231
+ calendar: validation.validationText
232
+ };
233
+ }
234
+ };
235
+ return /*#__PURE__*/_react2.default.createElement(_reactFinalForm.Form, {
236
+ onSubmit: () => {},
237
+ validate: errored
238
+ }, _ref => {
239
+ let {
240
+ handleSubmit,
241
+ invalid
242
+ } = _ref;
243
+ return /*#__PURE__*/_react2.default.createElement("form", null, /*#__PURE__*/_react2.default.createElement(_reactFinalForm.Field, {
244
+ name: "calendar"
245
+ }, props => /*#__PURE__*/_react2.default.createElement(_calendarInput.CalendarInput, _extends({}, props, {
246
+ date: date,
247
+ label: "Enter a date",
248
+ editable: true,
249
+ calendar: "gregory"
250
+ }, validation, propsFromParent, {
251
+ onDateSelect: date => {
252
+ var _propsFromParent$onDa;
253
+ setDate(date === null || date === void 0 ? void 0 : date.calendarDateString);
254
+ setValidation(date === null || date === void 0 ? void 0 : date.validation);
255
+ (_propsFromParent$onDa = propsFromParent.onDateSelect) === null || _propsFromParent$onDa === void 0 ? void 0 : _propsFromParent$onDa.call(propsFromParent, date);
256
+ }
257
+ }))), /*#__PURE__*/_react2.default.createElement(_button.Button, {
258
+ type: "submit",
259
+ disabled: invalid,
260
+ onClick: handleSubmit
261
+ }, "Submit"));
262
+ });
263
+ };
@@ -56,26 +56,43 @@ const CalendarInput = function () {
56
56
  numberingSystem,
57
57
  weekDayFormat
58
58
  }), [calendar, locale, numberingSystem, weekDayFormat]);
59
+ const onChooseDate = (date, validationOptions) => {
60
+ // Handling clearing (with clicking the Clear button, or deleting input)
61
+ if (clearable && (date === null || date === '')) {
62
+ parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
63
+ calendarDateString: null,
64
+ validation: {
65
+ valid: true
66
+ }
67
+ });
68
+ return;
69
+ }
70
+
71
+ // ToDo: This is now a workaround for handling choosing from the date picker
72
+ // where the blur event gets triggered causing a call with undefined first
73
+ if (date === undefined) {
74
+ return;
75
+ }
76
+ const validation = (0, _multiCalendarDates.validateDateString)(date, validationOptions);
77
+ parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
78
+ calendarDateString: date,
79
+ validation
80
+ });
81
+ };
82
+ const validationOptions = (0, _react.useMemo)(() => ({
83
+ calendar,
84
+ format,
85
+ minDateString: minDate,
86
+ maxDateString: maxDate,
87
+ strictValidation
88
+ }), [calendar, format, maxDate, minDate, strictValidation]);
59
89
  const pickerResults = (0, _multiCalendarDates.useDatePicker)({
60
90
  onDateSelect: result => {
61
- const validation = (0, _multiCalendarDates.validateDateString)(result.calendarDateString, {
62
- calendar,
63
- format,
64
- minDateString: minDate,
65
- maxDateString: maxDate,
66
- strictValidation
67
- });
91
+ onChooseDate(result.calendarDateString, validationOptions);
68
92
  setOpen(false);
69
- parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
70
- calendarDateString: result.calendarDateString,
71
- validation
72
- });
73
93
  },
74
94
  date,
75
- minDate: minDate,
76
- maxDate: maxDate,
77
- strictValidation: strictValidation,
78
- format: format,
95
+ ...validationOptions,
79
96
  options: useDatePickerOptions
80
97
  });
81
98
  const handleChange = e => {
@@ -83,17 +100,7 @@ const CalendarInput = function () {
83
100
  setPartialDate(e.value);
84
101
  };
85
102
  const handleBlur = (_, e) => {
86
- const validation = (0, _multiCalendarDates.validateDateString)(partialDate, {
87
- calendar,
88
- format,
89
- minDateString: minDate,
90
- maxDateString: maxDate,
91
- strictValidation
92
- });
93
- parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
94
- calendarDateString: partialDate,
95
- validation
96
- });
103
+ onChooseDate(partialDate, validationOptions);
97
104
  if (excludeRef.current && !excludeRef.current.contains(e.relatedTarget)) {
98
105
  setOpen(false);
99
106
  }
@@ -143,7 +150,7 @@ const CalendarInput = function () {
143
150
  secondary: true,
144
151
  small: true,
145
152
  onClick: () => {
146
- parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect(null);
153
+ onChooseDate(null);
147
154
  },
148
155
  type: "button"
149
156
  }, _index.default.t('Clear')))), open && /*#__PURE__*/_react.default.createElement(_layer.Layer, {
@@ -1,7 +1,16 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import { Button } from '@dhis2-ui/button';
1
3
  import { fireEvent, render, waitFor, within } from '@testing-library/react';
2
- import React from 'react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import React, { useState } from 'react';
6
+ import { Field, Form } from 'react-final-form';
3
7
  import { CalendarInput } from '../calendar-input.js';
4
8
  describe('Calendar Input', () => {
9
+ beforeEach(() => {
10
+ jest.useFakeTimers();
11
+ jest.setSystemTime(new Date('2024-10-22T09:05:00.000Z'));
12
+ });
13
+ afterEach(jest.useRealTimers);
5
14
  it('allow selection of a date through the calendar widget', async () => {
6
15
  const onDateSelectMock = jest.fn();
7
16
  const screen = render( /*#__PURE__*/React.createElement(CalendarInput, {
@@ -12,7 +21,7 @@ describe('Calendar Input', () => {
12
21
  fireEvent.focus(dateInput);
13
22
  const calendar = await screen.findByTestId('calendar');
14
23
  expect(calendar).toBeInTheDocument();
15
- const todayString = new Date().toISOString().slice(0, -14);
24
+ const todayString = '2024-10-22';
16
25
  const today = within(calendar).getByTestId(todayString);
17
26
  fireEvent.click(today);
18
27
  await waitFor(() => {
@@ -40,4 +49,210 @@ describe('Calendar Input', () => {
40
49
  calendarDateString: dateInputString
41
50
  }));
42
51
  });
43
- });
52
+ describe('validation', () => {
53
+ it('should validate minimum date', async () => {
54
+ const onDateSelectMock = jest.fn();
55
+ const screen = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
56
+ calendar: "gregory",
57
+ minDate: "2024-01-01",
58
+ onDateSelect: onDateSelectMock
59
+ }));
60
+ const dateInputString = '2023-10-12';
61
+ const dateInput = within(screen.getByTestId('dhis2-uicore-input')).getByRole('textbox');
62
+ userEvent.clear(dateInput);
63
+ userEvent.type(dateInput, dateInputString);
64
+ userEvent.tab();
65
+ expect(await screen.findByText('Date 2023-10-12 is less than the minimum allowed date 2024-01-01.'));
66
+ expect(onDateSelectMock).toHaveBeenCalledTimes(1);
67
+ });
68
+ it('should validate maximum date', async () => {
69
+ const {
70
+ getByTestId,
71
+ findByText
72
+ } = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
73
+ calendar: "gregory",
74
+ maxDate: "2024-01-01"
75
+ }));
76
+ const dateInputString = '2024-10-12';
77
+ const dateInput = within(getByTestId('dhis2-uicore-input')).getByRole('textbox');
78
+ userEvent.clear(dateInput);
79
+ userEvent.type(dateInput, dateInputString);
80
+ userEvent.tab();
81
+ expect(await findByText('Date 2024-10-12 is greater than the maximum allowed date 2024-01-01.'));
82
+ });
83
+ it('should validate date in ethiopic calendar', async () => {
84
+ const onDateSelectMock = jest.fn();
85
+ const {
86
+ getByTestId,
87
+ findByText,
88
+ queryByText
89
+ } = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
90
+ calendar: "ethiopian",
91
+ minDate: "2018-13-04",
92
+ onDateSelect: onDateSelectMock
93
+ }));
94
+ let dateInputString = '2018-13-02';
95
+ const dateInput = within(getByTestId('dhis2-uicore-input')).getByRole('textbox');
96
+ userEvent.clear(dateInput);
97
+ userEvent.type(dateInput, dateInputString);
98
+ userEvent.tab();
99
+ expect(await findByText('Date 2018-13-02 is less than the minimum allowed date 2018-13-04.'));
100
+ dateInputString = '2018-13-05';
101
+ userEvent.clear(dateInput);
102
+ userEvent.type(dateInput, dateInputString);
103
+ userEvent.tab();
104
+ expect(queryByText('Date 2018-13-04 is less than the minimum allowed date 2018-13-05.')).not.toBeInTheDocument();
105
+ dateInputString = '2018-13-07';
106
+ userEvent.clear(dateInput);
107
+ userEvent.type(dateInput, dateInputString);
108
+ userEvent.tab();
109
+ expect(await findByText('Invalid date in specified calendar')).toBeInTheDocument();
110
+ });
111
+ it('should validate date in nepali calendar', async () => {
112
+ const onDateSelectMock = jest.fn();
113
+ const {
114
+ getByTestId,
115
+ findByText,
116
+ queryByText
117
+ } = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
118
+ calendar: "nepali",
119
+ maxDate: "2080-05-30",
120
+ onDateSelect: onDateSelectMock
121
+ }));
122
+ let dateInputString = '2080-06-01';
123
+ const dateInput = within(getByTestId('dhis2-uicore-input')).getByRole('textbox');
124
+ userEvent.clear(dateInput);
125
+ userEvent.type(dateInput, dateInputString);
126
+ userEvent.tab();
127
+ expect(await findByText('Date 2080-06-01 is greater than the maximum allowed date 2080-05-30.'));
128
+ dateInputString = '2080-04-32';
129
+ userEvent.clear(dateInput);
130
+ userEvent.type(dateInput, dateInputString);
131
+ userEvent.tab();
132
+ expect(queryByText(/greater than the maximum allowed date/)).not.toBeInTheDocument();
133
+ dateInputString = '2080-01-32';
134
+ userEvent.clear(dateInput);
135
+ userEvent.type(dateInput, dateInputString);
136
+ userEvent.tab();
137
+ expect(await findByText('Invalid date in specified calendar')).toBeInTheDocument();
138
+ });
139
+ it('should validate from date picker', async () => {
140
+ const onDateSelectMock = jest.fn();
141
+ const {
142
+ queryByText,
143
+ getByText,
144
+ getByTestId
145
+ } = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
146
+ calendar: "gregory",
147
+ minDate: "2024-02-16",
148
+ onDateSelect: onDateSelectMock
149
+ }));
150
+ const dateInput = within(getByTestId('dhis2-uicore-input')).getByRole('textbox');
151
+ await userEvent.click(dateInput);
152
+ await userEvent.click(getByText('17'));
153
+ expect(queryByText('17')).not.toBeInTheDocument();
154
+
155
+ // Bug where callback used to be called first with undefined
156
+ expect(onDateSelectMock).toHaveBeenCalledTimes(1);
157
+ expect(onDateSelectMock).toHaveBeenCalledWith({
158
+ calendarDateString: '2024-10-17',
159
+ validation: {
160
+ error: false,
161
+ valid: true,
162
+ warning: false
163
+ }
164
+ });
165
+ });
166
+ it('should validate with Clear', async () => {
167
+ const onDateSelectMock = jest.fn();
168
+ const {
169
+ queryByText,
170
+ getByText,
171
+ getByTestId
172
+ } = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
173
+ calendar: "gregory",
174
+ minDate: "2024-02-16",
175
+ onDateSelect: onDateSelectMock,
176
+ clearable: true
177
+ }));
178
+ const dateInputString = '2023-10-12';
179
+ const dateInput = within(getByTestId('dhis2-uicore-input')).getByRole('textbox');
180
+ userEvent.clear(dateInput);
181
+ userEvent.type(dateInput, dateInputString);
182
+ userEvent.tab();
183
+ expect(getByTestId('dhis2-uiwidgets-calendar-inputfield-validation')).toBeInTheDocument();
184
+ await userEvent.click(getByText('Clear'));
185
+ expect(queryByText('17')).not.toBeInTheDocument();
186
+ expect(onDateSelectMock).toHaveBeenLastCalledWith({
187
+ calendarDateString: null,
188
+ validation: {
189
+ valid: true
190
+ }
191
+ });
192
+ });
193
+ it('should validate when Clearing manually (i.e. deleting text not using clear button)', async () => {
194
+ const onDateSelectMock = jest.fn();
195
+ const {
196
+ getByTestId
197
+ } = render( /*#__PURE__*/React.createElement(CalendarWithValidation, {
198
+ calendar: "gregory",
199
+ minDate: "2024-02-16",
200
+ onDateSelect: onDateSelectMock,
201
+ clearable: true
202
+ }));
203
+ const dateInputString = '2023-10-12';
204
+ const dateInput = within(getByTestId('dhis2-uicore-input')).getByRole('textbox');
205
+ userEvent.clear(dateInput);
206
+ userEvent.type(dateInput, dateInputString);
207
+ userEvent.tab();
208
+ expect(getByTestId('dhis2-uiwidgets-calendar-inputfield-validation')).toBeInTheDocument();
209
+ userEvent.clear(dateInput);
210
+ userEvent.tab();
211
+ expect(onDateSelectMock).toHaveBeenCalledWith({
212
+ calendarDateString: null,
213
+ validation: {
214
+ valid: true
215
+ }
216
+ });
217
+ });
218
+ });
219
+ });
220
+ const CalendarWithValidation = propsFromParent => {
221
+ const [date, setDate] = useState();
222
+ const [validation, setValidation] = useState({});
223
+ const errored = () => {
224
+ if (validation !== null && validation !== void 0 && validation.error) {
225
+ return {
226
+ calendar: validation.validationText
227
+ };
228
+ }
229
+ };
230
+ return /*#__PURE__*/React.createElement(Form, {
231
+ onSubmit: () => {},
232
+ validate: errored
233
+ }, _ref => {
234
+ let {
235
+ handleSubmit,
236
+ invalid
237
+ } = _ref;
238
+ return /*#__PURE__*/React.createElement("form", null, /*#__PURE__*/React.createElement(Field, {
239
+ name: "calendar"
240
+ }, props => /*#__PURE__*/React.createElement(CalendarInput, _extends({}, props, {
241
+ date: date,
242
+ label: "Enter a date",
243
+ editable: true,
244
+ calendar: "gregory"
245
+ }, validation, propsFromParent, {
246
+ onDateSelect: date => {
247
+ var _propsFromParent$onDa;
248
+ setDate(date === null || date === void 0 ? void 0 : date.calendarDateString);
249
+ setValidation(date === null || date === void 0 ? void 0 : date.validation);
250
+ (_propsFromParent$onDa = propsFromParent.onDateSelect) === null || _propsFromParent$onDa === void 0 ? void 0 : _propsFromParent$onDa.call(propsFromParent, date);
251
+ }
252
+ }))), /*#__PURE__*/React.createElement(Button, {
253
+ type: "submit",
254
+ disabled: invalid,
255
+ onClick: handleSubmit
256
+ }, "Submit"));
257
+ });
258
+ };
@@ -47,26 +47,43 @@ export const CalendarInput = function () {
47
47
  numberingSystem,
48
48
  weekDayFormat
49
49
  }), [calendar, locale, numberingSystem, weekDayFormat]);
50
+ const onChooseDate = (date, validationOptions) => {
51
+ // Handling clearing (with clicking the Clear button, or deleting input)
52
+ if (clearable && (date === null || date === '')) {
53
+ parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
54
+ calendarDateString: null,
55
+ validation: {
56
+ valid: true
57
+ }
58
+ });
59
+ return;
60
+ }
61
+
62
+ // ToDo: This is now a workaround for handling choosing from the date picker
63
+ // where the blur event gets triggered causing a call with undefined first
64
+ if (date === undefined) {
65
+ return;
66
+ }
67
+ const validation = validateDateString(date, validationOptions);
68
+ parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
69
+ calendarDateString: date,
70
+ validation
71
+ });
72
+ };
73
+ const validationOptions = useMemo(() => ({
74
+ calendar,
75
+ format,
76
+ minDateString: minDate,
77
+ maxDateString: maxDate,
78
+ strictValidation
79
+ }), [calendar, format, maxDate, minDate, strictValidation]);
50
80
  const pickerResults = useDatePicker({
51
81
  onDateSelect: result => {
52
- const validation = validateDateString(result.calendarDateString, {
53
- calendar,
54
- format,
55
- minDateString: minDate,
56
- maxDateString: maxDate,
57
- strictValidation
58
- });
82
+ onChooseDate(result.calendarDateString, validationOptions);
59
83
  setOpen(false);
60
- parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
61
- calendarDateString: result.calendarDateString,
62
- validation
63
- });
64
84
  },
65
85
  date,
66
- minDate: minDate,
67
- maxDate: maxDate,
68
- strictValidation: strictValidation,
69
- format: format,
86
+ ...validationOptions,
70
87
  options: useDatePickerOptions
71
88
  });
72
89
  const handleChange = e => {
@@ -74,17 +91,7 @@ export const CalendarInput = function () {
74
91
  setPartialDate(e.value);
75
92
  };
76
93
  const handleBlur = (_, e) => {
77
- const validation = validateDateString(partialDate, {
78
- calendar,
79
- format,
80
- minDateString: minDate,
81
- maxDateString: maxDate,
82
- strictValidation
83
- });
84
- parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect({
85
- calendarDateString: partialDate,
86
- validation
87
- });
94
+ onChooseDate(partialDate, validationOptions);
88
95
  if (excludeRef.current && !excludeRef.current.contains(e.relatedTarget)) {
89
96
  setOpen(false);
90
97
  }
@@ -134,7 +141,7 @@ export const CalendarInput = function () {
134
141
  secondary: true,
135
142
  small: true,
136
143
  onClick: () => {
137
- parentOnDateSelect === null || parentOnDateSelect === void 0 ? void 0 : parentOnDateSelect(null);
144
+ onChooseDate(null);
138
145
  },
139
146
  type: "button"
140
147
  }, i18n.t('Clear')))), open && /*#__PURE__*/React.createElement(Layer, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhis2-ui/calendar",
3
- "version": "10.0.0-alpha.5",
3
+ "version": "10.0.0-alpha.6",
4
4
  "description": "UI Calendar",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,15 +33,15 @@
33
33
  "styled-jsx": "^4"
34
34
  },
35
35
  "dependencies": {
36
- "@dhis2-ui/button": "10.0.0-alpha.5",
37
- "@dhis2-ui/card": "10.0.0-alpha.5",
38
- "@dhis2-ui/input": "10.0.0-alpha.5",
39
- "@dhis2-ui/layer": "10.0.0-alpha.5",
40
- "@dhis2-ui/popper": "10.0.0-alpha.5",
36
+ "@dhis2-ui/button": "10.0.0-alpha.6",
37
+ "@dhis2-ui/card": "10.0.0-alpha.6",
38
+ "@dhis2-ui/input": "10.0.0-alpha.6",
39
+ "@dhis2-ui/layer": "10.0.0-alpha.6",
40
+ "@dhis2-ui/popper": "10.0.0-alpha.6",
41
41
  "@dhis2/multi-calendar-dates": "2.0.0-alpha.5",
42
42
  "@dhis2/prop-types": "^3.1.2",
43
- "@dhis2/ui-constants": "10.0.0-alpha.5",
44
- "@dhis2/ui-icons": "10.0.0-alpha.5",
43
+ "@dhis2/ui-constants": "10.0.0-alpha.6",
44
+ "@dhis2/ui-icons": "10.0.0-alpha.6",
45
45
  "classnames": "^2.3.1",
46
46
  "prop-types": "^15.7.2"
47
47
  },