@dhis2-ui/calendar 10.0.0-alpha.4 → 10.0.0-alpha.6
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/build/cjs/calendar-input/__tests__/calendar-input.test.js +220 -3
- package/build/cjs/calendar-input/calendar-input.js +36 -27
- package/build/cjs/stories/calendar-input.prod.stories.js +3 -0
- package/build/es/calendar-input/__tests__/calendar-input.test.js +218 -3
- package/build/es/calendar-input/calendar-input.js +36 -27
- package/build/es/stories/calendar-input.prod.stories.js +3 -0
- package/package.json +9 -9
|
@@ -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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
76
|
-
maxDate: maxDate,
|
|
77
|
-
strictValidation: strictValidation,
|
|
78
|
-
format: format,
|
|
95
|
+
...validationOptions,
|
|
79
96
|
options: useDatePickerOptions
|
|
80
97
|
});
|
|
81
98
|
const handleChange = e => {
|
|
@@ -83,23 +100,15 @@ const CalendarInput = function () {
|
|
|
83
100
|
setPartialDate(e.value);
|
|
84
101
|
};
|
|
85
102
|
const handleBlur = (_, e) => {
|
|
86
|
-
|
|
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
|
}
|
|
100
107
|
};
|
|
101
108
|
const onFocus = () => {
|
|
109
|
+
var _rest$onFocus;
|
|
102
110
|
setOpen(true);
|
|
111
|
+
rest === null || rest === void 0 ? void 0 : (_rest$onFocus = rest.onFocus) === null || _rest$onFocus === void 0 ? void 0 : _rest$onFocus.call(rest);
|
|
103
112
|
};
|
|
104
113
|
const languageDirection = (0, _multiCalendarDates.useResolvedDirection)(dir, locale);
|
|
105
114
|
const calendarProps = (0, _react.useMemo)(() => {
|
|
@@ -141,7 +150,7 @@ const CalendarInput = function () {
|
|
|
141
150
|
secondary: true,
|
|
142
151
|
small: true,
|
|
143
152
|
onClick: () => {
|
|
144
|
-
|
|
153
|
+
onChooseDate(null);
|
|
145
154
|
},
|
|
146
155
|
type: "button"
|
|
147
156
|
}, _index.default.t('Clear')))), open && /*#__PURE__*/_react.default.createElement(_layer.Layer, {
|
|
@@ -131,6 +131,9 @@ function CalendarWithEditiableInput() {
|
|
|
131
131
|
const date = selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.calendarDateString;
|
|
132
132
|
setDate(date);
|
|
133
133
|
},
|
|
134
|
+
onFocus: () => {
|
|
135
|
+
console.log('focused');
|
|
136
|
+
},
|
|
134
137
|
width: "400px",
|
|
135
138
|
minDate: "2020-07-01",
|
|
136
139
|
maxDate: "2020-07-09",
|
|
@@ -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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
67
|
-
maxDate: maxDate,
|
|
68
|
-
strictValidation: strictValidation,
|
|
69
|
-
format: format,
|
|
86
|
+
...validationOptions,
|
|
70
87
|
options: useDatePickerOptions
|
|
71
88
|
});
|
|
72
89
|
const handleChange = e => {
|
|
@@ -74,23 +91,15 @@ export const CalendarInput = function () {
|
|
|
74
91
|
setPartialDate(e.value);
|
|
75
92
|
};
|
|
76
93
|
const handleBlur = (_, e) => {
|
|
77
|
-
|
|
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
|
}
|
|
91
98
|
};
|
|
92
99
|
const onFocus = () => {
|
|
100
|
+
var _rest$onFocus;
|
|
93
101
|
setOpen(true);
|
|
102
|
+
rest === null || rest === void 0 ? void 0 : (_rest$onFocus = rest.onFocus) === null || _rest$onFocus === void 0 ? void 0 : _rest$onFocus.call(rest);
|
|
94
103
|
};
|
|
95
104
|
const languageDirection = useResolvedDirection(dir, locale);
|
|
96
105
|
const calendarProps = useMemo(() => {
|
|
@@ -132,7 +141,7 @@ export const CalendarInput = function () {
|
|
|
132
141
|
secondary: true,
|
|
133
142
|
small: true,
|
|
134
143
|
onClick: () => {
|
|
135
|
-
|
|
144
|
+
onChooseDate(null);
|
|
136
145
|
},
|
|
137
146
|
type: "button"
|
|
138
147
|
}, i18n.t('Clear')))), open && /*#__PURE__*/React.createElement(Layer, {
|
|
@@ -117,6 +117,9 @@ export function CalendarWithEditiableInput() {
|
|
|
117
117
|
const date = selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.calendarDateString;
|
|
118
118
|
setDate(date);
|
|
119
119
|
},
|
|
120
|
+
onFocus: () => {
|
|
121
|
+
console.log('focused');
|
|
122
|
+
},
|
|
120
123
|
width: "400px",
|
|
121
124
|
minDate: "2020-07-01",
|
|
122
125
|
maxDate: "2020-07-09",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2-ui/calendar",
|
|
3
|
-
"version": "10.0.0-alpha.
|
|
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.
|
|
37
|
-
"@dhis2-ui/card": "10.0.0-alpha.
|
|
38
|
-
"@dhis2-ui/input": "10.0.0-alpha.
|
|
39
|
-
"@dhis2-ui/layer": "10.0.0-alpha.
|
|
40
|
-
"@dhis2-ui/popper": "10.0.0-alpha.
|
|
41
|
-
"@dhis2/multi-calendar-dates": "2.0.0-alpha.
|
|
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
|
+
"@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.
|
|
44
|
-
"@dhis2/ui-icons": "10.0.0-alpha.
|
|
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
|
},
|