@weni/unnnic-system 3.35.2-alpha.2 → 3.35.2-alpha.3
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/dist/components/DateFilter/DateFilter.vue.mjs +25 -29
- package/dist/components/InputDatePicker/InputDatePicker.vue.mjs +1 -1
- package/dist/components/InputDatePicker/InputDatePicker.vue2.mjs +38 -32
- package/dist/components/InputDatePicker/InputDatePicker2.css +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/node_modules/date-fns/_lib/addLeadingZeros.mjs +7 -0
- package/dist/node_modules/date-fns/_lib/defaultOptions.mjs +7 -0
- package/dist/node_modules/date-fns/_lib/format/formatters.mjs +515 -0
- package/dist/node_modules/date-fns/_lib/format/lightFormatters.mjs +59 -0
- package/dist/node_modules/date-fns/_lib/format/longFormatters.mjs +52 -0
- package/dist/node_modules/date-fns/_lib/getTimezoneOffsetInMilliseconds.mjs +18 -0
- package/dist/node_modules/date-fns/_lib/normalizeDates.mjs +11 -0
- package/dist/node_modules/date-fns/_lib/protectedTokens.mjs +20 -0
- package/dist/node_modules/date-fns/addDays.mjs +9 -0
- package/dist/node_modules/date-fns/constants.mjs +9 -0
- package/dist/node_modules/date-fns/constructFrom.mjs +7 -0
- package/dist/node_modules/date-fns/differenceInCalendarDays.mjs +15 -0
- package/dist/node_modules/date-fns/format.mjs +58 -0
- package/dist/node_modules/date-fns/getDayOfYear.mjs +10 -0
- package/dist/node_modules/date-fns/getDefaultOptions.mjs +7 -0
- package/dist/node_modules/date-fns/getISODay.mjs +8 -0
- package/dist/node_modules/date-fns/getISOWeek.mjs +11 -0
- package/dist/node_modules/date-fns/getISOWeekYear.mjs +14 -0
- package/dist/node_modules/date-fns/getWeek.mjs +11 -0
- package/dist/node_modules/date-fns/getWeekYear.mjs +16 -0
- package/dist/node_modules/date-fns/isDate.mjs +6 -0
- package/dist/node_modules/date-fns/isValid.mjs +8 -0
- package/dist/node_modules/date-fns/locale/_lib/buildFormatLongFn.mjs +9 -0
- package/dist/node_modules/date-fns/locale/_lib/buildLocalizeFn.mjs +18 -0
- package/dist/node_modules/date-fns/locale/_lib/buildMatchFn.mjs +31 -0
- package/dist/node_modules/date-fns/locale/_lib/buildMatchPatternFn.mjs +15 -0
- package/dist/node_modules/date-fns/locale/en-US/_lib/formatDistance.mjs +70 -0
- package/dist/node_modules/date-fns/locale/en-US/_lib/formatLong.mjs +33 -0
- package/dist/node_modules/date-fns/locale/en-US/_lib/formatRelative.mjs +11 -0
- package/dist/node_modules/date-fns/locale/en-US/_lib/localize.mjs +155 -0
- package/dist/node_modules/date-fns/locale/en-US/_lib/match.mjs +110 -0
- package/dist/node_modules/date-fns/locale/en-US.mjs +20 -0
- package/dist/node_modules/date-fns/parse/_lib/Parser.mjs +22 -0
- package/dist/node_modules/date-fns/parse/_lib/Setter.mjs +41 -0
- package/dist/node_modules/date-fns/parse/_lib/constants.mjs +49 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/AMPMMidnightParser.mjs +49 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/AMPMParser.mjs +49 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/DateParser.mjs +61 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/DayOfYearParser.mjs +51 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/DayParser.mjs +45 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/DayPeriodParser.mjs +49 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/EraParser.mjs +30 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/ExtendedYearParser.mjs +21 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/FractionOfSecondParser.mjs +22 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/Hour0To11Parser.mjs +32 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/Hour0to23Parser.mjs +32 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/Hour1To24Parser.mjs +33 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/Hour1to12Parser.mjs +33 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/ISODayParser.mjs +99 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/ISOTimezoneParser.mjs +48 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/ISOTimezoneWithZParser.mjs +48 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/ISOWeekParser.mjs +49 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/ISOWeekYearParser.mjs +40 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/LocalDayParser.mjs +74 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/LocalWeekParser.mjs +48 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/LocalWeekYearParser.mjs +69 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/MinuteParser.mjs +32 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/MonthParser.mjs +71 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/QuarterParser.mjs +70 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/SecondParser.mjs +32 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/StandAloneLocalDayParser.mjs +74 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/StandAloneMonthParser.mjs +71 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/StandAloneQuarterParser.mjs +70 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/TimestampMillisecondsParser.mjs +22 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/TimestampSecondsParser.mjs +22 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers/YearParser.mjs +49 -0
- package/dist/node_modules/date-fns/parse/_lib/parsers.mjs +67 -0
- package/dist/node_modules/date-fns/parse/_lib/utils.mjs +103 -0
- package/dist/node_modules/date-fns/parse.mjs +88 -0
- package/dist/node_modules/date-fns/setDay.mjs +11 -0
- package/dist/node_modules/date-fns/setISODay.mjs +10 -0
- package/dist/node_modules/date-fns/setISOWeek.mjs +9 -0
- package/dist/node_modules/date-fns/setWeek.mjs +9 -0
- package/dist/node_modules/date-fns/startOfDay.mjs +8 -0
- package/dist/node_modules/date-fns/startOfISOWeek.mjs +7 -0
- package/dist/node_modules/date-fns/startOfISOWeekYear.mjs +10 -0
- package/dist/node_modules/date-fns/startOfWeek.mjs +10 -0
- package/dist/node_modules/date-fns/startOfWeekYear.mjs +12 -0
- package/dist/node_modules/date-fns/startOfYear.mjs +8 -0
- package/dist/node_modules/date-fns/toDate.mjs +7 -0
- package/dist/node_modules/date-fns/transpose.mjs +17 -0
- package/dist/style.css +1 -1
- package/dist/unnnic.umd.js +19 -19
- package/dist/utils/formatDate.mjs +30 -0
- package/package.json +2 -1
- package/src/components/DateFilter/DateFilter.vue +12 -9
- package/src/components/DateFilter/__test__/DateFilter.spec.js +41 -0
- package/src/components/InputDatePicker/InputDatePicker.vue +26 -14
- package/src/components/InputDatePicker/__test__/InputDatePicker.spec.js +112 -0
- package/src/components/InputDatePicker/__test__/formatDate.spec.ts +75 -0
- package/src/stories/DateFilter.stories.js +1 -0
- package/src/stories/InputDatePicker.stories.js +3 -0
- package/src/utils/formatDate.ts +76 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./date.mjs";
|
|
2
|
+
import { parse as f } from "../node_modules/date-fns/parse.mjs";
|
|
3
|
+
import { isValid as l } from "../node_modules/date-fns/isValid.mjs";
|
|
4
|
+
import { format as s } from "../node_modules/date-fns/format.mjs";
|
|
5
|
+
import a from "../node_modules/dayjs/dayjs.min.mjs";
|
|
6
|
+
function D(t) {
|
|
7
|
+
return t.replaceAll("YYYY", "yyyy").replaceAll("DD", "dd");
|
|
8
|
+
}
|
|
9
|
+
function o(t) {
|
|
10
|
+
return t.replaceAll("DD", "D").replaceAll("MM", "M");
|
|
11
|
+
}
|
|
12
|
+
function c(t) {
|
|
13
|
+
return o(t).replaceAll("YYYY", "yyyy").replaceAll("D", "d");
|
|
14
|
+
}
|
|
15
|
+
function p(t, n, r) {
|
|
16
|
+
return (r && typeof t == "string" ? a(t, o(r)) : a(t)).format(n);
|
|
17
|
+
}
|
|
18
|
+
function m(t, n, r) {
|
|
19
|
+
let e;
|
|
20
|
+
return t instanceof Date ? e = t : r ? e = f(t, c(r), /* @__PURE__ */ new Date()) : e = new Date(t), l(e) ? s(e, D(n)) : "Invalid Date";
|
|
21
|
+
}
|
|
22
|
+
function P(t, n, r = {}) {
|
|
23
|
+
const { parseFormat: e, useDateFns: i = !1 } = r;
|
|
24
|
+
return i ? m(t, n, e) : p(t, n, e);
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
P as formatDate,
|
|
28
|
+
m as formatWithDateFns,
|
|
29
|
+
p as formatWithDayjs
|
|
30
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weni/unnnic-system",
|
|
3
|
-
"version": "3.35.2-alpha.
|
|
3
|
+
"version": "3.35.2-alpha.3",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"@iconify/vue": "^5.0.0",
|
|
92
92
|
"@vueuse/components": "^10.4.1",
|
|
93
93
|
"@vueuse/core": "^14.0.0",
|
|
94
|
+
"date-fns": "^4.4.0",
|
|
94
95
|
"dayjs": "^1.11.23",
|
|
95
96
|
"emoji-mart-vue-fast": "^15.0.5",
|
|
96
97
|
"lucide-vue-next": "^0.546.0",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script>
|
|
17
|
-
import
|
|
17
|
+
import { formatDate } from '@/utils/formatDate';
|
|
18
18
|
import UnnnicInput from '../Input/Input.vue';
|
|
19
19
|
|
|
20
20
|
export default {
|
|
@@ -45,23 +45,26 @@ export default {
|
|
|
45
45
|
type: String,
|
|
46
46
|
default: '',
|
|
47
47
|
},
|
|
48
|
+
useDateFns: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
48
52
|
},
|
|
49
53
|
computed: {
|
|
50
54
|
dateRange() {
|
|
51
55
|
let range = '';
|
|
56
|
+
const outputFormat = this.dateFormat.replaceAll('/', '');
|
|
52
57
|
|
|
53
58
|
if (this.startDate) {
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
);
|
|
57
|
-
range += formattedDate.toString();
|
|
59
|
+
range += formatDate(this.startDate, outputFormat, {
|
|
60
|
+
useDateFns: this.useDateFns,
|
|
61
|
+
});
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
if (this.endDate) {
|
|
61
|
-
|
|
62
|
-
this.
|
|
63
|
-
);
|
|
64
|
-
range += formattedDate.toString();
|
|
65
|
+
range += formatDate(this.endDate, outputFormat, {
|
|
66
|
+
useDateFns: this.useDateFns,
|
|
67
|
+
});
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
return range;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import DateFilter from '../DateFilter.vue';
|
|
5
|
+
|
|
6
|
+
const factory = (props = {}) =>
|
|
7
|
+
mount(DateFilter, {
|
|
8
|
+
props,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe('DateFilter.vue', () => {
|
|
12
|
+
it('computes dateRange from start and end dates with dayjs', () => {
|
|
13
|
+
const wrapper = factory({
|
|
14
|
+
startDate: new Date(2025, 0, 10),
|
|
15
|
+
endDate: new Date(2025, 0, 20),
|
|
16
|
+
dateFormat: 'DD/MM/YYYY',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(wrapper.vm.dateRange).toBe('1001202520012025');
|
|
20
|
+
wrapper.unmount();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('computes dateRange from start and end dates with date-fns', () => {
|
|
24
|
+
const wrapper = factory({
|
|
25
|
+
startDate: new Date(2025, 0, 10),
|
|
26
|
+
endDate: new Date(2025, 0, 20),
|
|
27
|
+
dateFormat: 'DD/MM/YYYY',
|
|
28
|
+
useDateFns: true,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(wrapper.vm.dateRange).toBe('1001202520012025');
|
|
32
|
+
wrapper.unmount();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('returns an empty dateRange when there is no date selected', () => {
|
|
36
|
+
const wrapper = factory();
|
|
37
|
+
|
|
38
|
+
expect(wrapper.vm.dateRange).toBe('');
|
|
39
|
+
wrapper.unmount();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
|
|
54
54
|
<script setup lang="ts">
|
|
55
55
|
import { computed, ref, useSlots } from 'vue';
|
|
56
|
-
import
|
|
56
|
+
import { formatDate } from '@/utils/formatDate';
|
|
57
57
|
|
|
58
58
|
import UnnnicInput from '../Input/Input.vue';
|
|
59
59
|
import UnnnicDatePicker from '../DatePicker/DatePicker.vue';
|
|
@@ -110,6 +110,8 @@ interface InputDatePickerProps {
|
|
|
110
110
|
disabled?: boolean;
|
|
111
111
|
|
|
112
112
|
disableShowOverwrittenValue?: boolean;
|
|
113
|
+
|
|
114
|
+
useDateFns?: boolean;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
const props = withDefaults(defineProps<InputDatePickerProps>(), {
|
|
@@ -133,6 +135,7 @@ const props = withDefaults(defineProps<InputDatePickerProps>(), {
|
|
|
133
135
|
periodBaseDate: '',
|
|
134
136
|
disabled: false,
|
|
135
137
|
disableShowOverwrittenValue: false,
|
|
138
|
+
useDateFns: false,
|
|
136
139
|
});
|
|
137
140
|
|
|
138
141
|
const emit = defineEmits<{
|
|
@@ -146,6 +149,17 @@ const popoverAlign = computed<'start' | 'end'>(() =>
|
|
|
146
149
|
props.position === 'right' ? 'end' : 'start',
|
|
147
150
|
);
|
|
148
151
|
|
|
152
|
+
function formatPickerDate(
|
|
153
|
+
value: string,
|
|
154
|
+
outputFormat: string,
|
|
155
|
+
parseFormat?: string,
|
|
156
|
+
) {
|
|
157
|
+
return formatDate(value, outputFormat, {
|
|
158
|
+
parseFormat,
|
|
159
|
+
useDateFns: props.useDateFns,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
149
163
|
const inputText = computed(() => {
|
|
150
164
|
if (props.disableShowOverwrittenValue) {
|
|
151
165
|
return filterText.value || '';
|
|
@@ -160,11 +174,11 @@ const filterText = computed(() => {
|
|
|
160
174
|
const { start, end } = props.modelValue || {};
|
|
161
175
|
|
|
162
176
|
if (start) {
|
|
163
|
-
dates.push(
|
|
177
|
+
dates.push(formatPickerDate(start, props.inputFormat || '', props.format));
|
|
164
178
|
}
|
|
165
179
|
|
|
166
180
|
if (end) {
|
|
167
|
-
dates.push(
|
|
181
|
+
dates.push(formatPickerDate(end, props.inputFormat || '', props.format));
|
|
168
182
|
}
|
|
169
183
|
|
|
170
184
|
if (!dates.length) {
|
|
@@ -178,38 +192,36 @@ const filterText = computed(() => {
|
|
|
178
192
|
|
|
179
193
|
const initialStartDate = computed<string | undefined>(() => {
|
|
180
194
|
return props.modelValue.start
|
|
181
|
-
?
|
|
195
|
+
? formatPickerDate(props.modelValue.start, 'MM DD YYYY', props.format)
|
|
182
196
|
: undefined;
|
|
183
197
|
});
|
|
184
198
|
|
|
185
199
|
const initialEndDate = computed<string | undefined>(() => {
|
|
186
200
|
return props.modelValue.end
|
|
187
|
-
?
|
|
201
|
+
? formatPickerDate(props.modelValue.end, 'MM DD YYYY', props.format)
|
|
188
202
|
: undefined;
|
|
189
203
|
});
|
|
190
204
|
|
|
191
205
|
function emitSelectDate(date: { startDate: string; endDate: string }) {
|
|
192
206
|
const { startDate, endDate } = date;
|
|
193
207
|
const formattedDates: DateRangeValue = {
|
|
194
|
-
start:
|
|
195
|
-
end:
|
|
208
|
+
start: formatPickerDate(startDate, props.format, 'MM-DD-YYYY'),
|
|
209
|
+
end: formatPickerDate(endDate, props.format, 'MM-DD-YYYY'),
|
|
196
210
|
};
|
|
197
211
|
|
|
198
212
|
emit('selectDate', formattedDates);
|
|
199
213
|
}
|
|
200
214
|
|
|
201
215
|
function changeDate(value: { startDate: string; endDate: string }) {
|
|
202
|
-
const startDate = value.startDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
|
|
203
|
-
|
|
204
|
-
const endDate = value.endDate.replace(/(\d+)-(\d+)-(\d+)/, '$3-$1-$2');
|
|
205
|
-
|
|
206
216
|
isPopoverOpen.value = false;
|
|
207
217
|
|
|
208
218
|
emit('update:model-value', {
|
|
209
|
-
start: startDate
|
|
210
|
-
?
|
|
219
|
+
start: value.startDate
|
|
220
|
+
? formatPickerDate(value.startDate, props.format, 'MM-DD-YYYY')
|
|
221
|
+
: null,
|
|
222
|
+
end: value.endDate
|
|
223
|
+
? formatPickerDate(value.endDate, props.format, 'MM-DD-YYYY')
|
|
211
224
|
: null,
|
|
212
|
-
end: endDate ? dayjs(endDate, 'YYYY-MM-DD').format(props.format) : null,
|
|
213
225
|
});
|
|
214
226
|
}
|
|
215
227
|
|
|
@@ -83,6 +83,21 @@ describe('InputDatePicker.vue', () => {
|
|
|
83
83
|
withDates.unmount();
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
it('computes filterText from start and end dates with date-fns', () => {
|
|
87
|
+
const withDates = factory({
|
|
88
|
+
modelValue: {
|
|
89
|
+
start: '2025-01-10',
|
|
90
|
+
end: '2025-01-20',
|
|
91
|
+
},
|
|
92
|
+
format: 'YYYY-MM-DD',
|
|
93
|
+
inputFormat: 'MM-DD-YYYY',
|
|
94
|
+
useDateFns: true,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(withDates.vm.filterText).toBe('01-10-2025 ~ 01-20-2025');
|
|
98
|
+
withDates.unmount();
|
|
99
|
+
});
|
|
100
|
+
|
|
86
101
|
it('computes initialStartDate and initialEndDate for DatePicker', () => {
|
|
87
102
|
const withDates = factory({
|
|
88
103
|
modelValue: {
|
|
@@ -96,6 +111,20 @@ describe('InputDatePicker.vue', () => {
|
|
|
96
111
|
withDates.unmount();
|
|
97
112
|
});
|
|
98
113
|
|
|
114
|
+
it('computes initialStartDate and initialEndDate with date-fns', () => {
|
|
115
|
+
const withDates = factory({
|
|
116
|
+
modelValue: {
|
|
117
|
+
start: '2025-01-10',
|
|
118
|
+
end: '2025-01-20',
|
|
119
|
+
},
|
|
120
|
+
useDateFns: true,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(withDates.vm.initialStartDate).toBe('01 10 2025');
|
|
124
|
+
expect(withDates.vm.initialEndDate).toBe('01 20 2025');
|
|
125
|
+
withDates.unmount();
|
|
126
|
+
});
|
|
127
|
+
|
|
99
128
|
it('emits selectDate with formatted dates when DatePicker emits change', async () => {
|
|
100
129
|
wrapper.vm.isPopoverOpen = true;
|
|
101
130
|
await wrapper.vm.$nextTick();
|
|
@@ -119,6 +148,65 @@ describe('InputDatePicker.vue', () => {
|
|
|
119
148
|
});
|
|
120
149
|
});
|
|
121
150
|
|
|
151
|
+
it('emits selectDate with formatted dates using date-fns', async () => {
|
|
152
|
+
wrapper = factory({ useDateFns: true });
|
|
153
|
+
wrapper.vm.isPopoverOpen = true;
|
|
154
|
+
await wrapper.vm.$nextTick();
|
|
155
|
+
|
|
156
|
+
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
157
|
+
|
|
158
|
+
await datePicker.vm.$emit('change', {
|
|
159
|
+
startDate: '01-10-2025',
|
|
160
|
+
endDate: '01-20-2025',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const emitted = wrapper.emitted('selectDate');
|
|
164
|
+
expect(emitted).toBeTruthy();
|
|
165
|
+
|
|
166
|
+
const [formatted] = emitted[0];
|
|
167
|
+
expect(formatted).toEqual({
|
|
168
|
+
start: '2025-01-10',
|
|
169
|
+
end: '2025-01-20',
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('formats unpadded DatePicker dates on selectDate', async () => {
|
|
174
|
+
wrapper.vm.isPopoverOpen = true;
|
|
175
|
+
await wrapper.vm.$nextTick();
|
|
176
|
+
|
|
177
|
+
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
178
|
+
|
|
179
|
+
await datePicker.vm.$emit('change', {
|
|
180
|
+
startDate: '9-21-2026',
|
|
181
|
+
endDate: '9-22-2026',
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const [formatted] = wrapper.emitted('selectDate')[0];
|
|
185
|
+
expect(formatted).toEqual({
|
|
186
|
+
start: '2026-09-21',
|
|
187
|
+
end: '2026-09-22',
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('formats unpadded DatePicker dates on submit with date-fns', async () => {
|
|
192
|
+
wrapper = factory({ useDateFns: true });
|
|
193
|
+
wrapper.vm.isPopoverOpen = true;
|
|
194
|
+
await wrapper.vm.$nextTick();
|
|
195
|
+
|
|
196
|
+
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
197
|
+
|
|
198
|
+
await datePicker.vm.$emit('submit', {
|
|
199
|
+
startDate: '9-21-2026',
|
|
200
|
+
endDate: '9-22-2026',
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const [newValue] = wrapper.emitted('update:model-value')[0];
|
|
204
|
+
expect(newValue).toEqual({
|
|
205
|
+
start: '2026-09-21',
|
|
206
|
+
end: '2026-09-22',
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
122
210
|
it('emits update:model-value and closes dropdown when DatePicker emits submit', async () => {
|
|
123
211
|
wrapper.vm.isPopoverOpen = true;
|
|
124
212
|
await wrapper.vm.$nextTick();
|
|
@@ -144,6 +232,30 @@ describe('InputDatePicker.vue', () => {
|
|
|
144
232
|
expect(wrapper.vm.isPopoverOpen).toBe(false);
|
|
145
233
|
});
|
|
146
234
|
|
|
235
|
+
it('emits update:model-value with date-fns and closes dropdown on submit', async () => {
|
|
236
|
+
wrapper = factory({ useDateFns: true });
|
|
237
|
+
wrapper.vm.isPopoverOpen = true;
|
|
238
|
+
await wrapper.vm.$nextTick();
|
|
239
|
+
|
|
240
|
+
const datePicker = wrapper.findComponent({ name: 'UnnnicDatePicker' });
|
|
241
|
+
|
|
242
|
+
await datePicker.vm.$emit('submit', {
|
|
243
|
+
startDate: '01-10-2025',
|
|
244
|
+
endDate: '01-20-2025',
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const emitted = wrapper.emitted('update:model-value');
|
|
248
|
+
expect(emitted).toBeTruthy();
|
|
249
|
+
|
|
250
|
+
const [newValue] = emitted[0];
|
|
251
|
+
expect(newValue).toEqual({
|
|
252
|
+
start: '2025-01-10',
|
|
253
|
+
end: '2025-01-20',
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(wrapper.vm.isPopoverOpen).toBe(false);
|
|
257
|
+
});
|
|
258
|
+
|
|
147
259
|
it('passes minDate, maxDate, options and periodBaseDate down to DatePicker', async () => {
|
|
148
260
|
const props = {
|
|
149
261
|
minDate: '2025-01-01',
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
formatDate,
|
|
5
|
+
formatWithDateFns,
|
|
6
|
+
formatWithDayjs,
|
|
7
|
+
} from '@/utils/formatDate';
|
|
8
|
+
|
|
9
|
+
describe('formatDate helpers', () => {
|
|
10
|
+
it('formats ISO dates to input format with dayjs', () => {
|
|
11
|
+
expect(formatWithDayjs('2025-01-10', 'MM-DD-YYYY', 'YYYY-MM-DD')).toBe(
|
|
12
|
+
'01-10-2025',
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('formats ISO dates to input format with date-fns using dayjs tokens', () => {
|
|
17
|
+
expect(formatWithDateFns('2025-01-10', 'MM-DD-YYYY', 'YYYY-MM-DD')).toBe(
|
|
18
|
+
'01-10-2025',
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('formats picker dates to MM DD YYYY with both libraries', () => {
|
|
23
|
+
expect(formatWithDayjs('2025-01-10', 'MM DD YYYY', 'YYYY-MM-DD')).toBe(
|
|
24
|
+
'01 10 2025',
|
|
25
|
+
);
|
|
26
|
+
expect(formatWithDateFns('2025-01-10', 'MM DD YYYY', 'YYYY-MM-DD')).toBe(
|
|
27
|
+
'01 10 2025',
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('parses MM-DD-YYYY into YYYY-MM-DD with both libraries', () => {
|
|
32
|
+
expect(formatWithDayjs('01-10-2025', 'YYYY-MM-DD', 'MM-DD-YYYY')).toBe(
|
|
33
|
+
'2025-01-10',
|
|
34
|
+
);
|
|
35
|
+
expect(formatWithDateFns('01-10-2025', 'YYYY-MM-DD', 'MM-DD-YYYY')).toBe(
|
|
36
|
+
'2025-01-10',
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('parses unpadded DatePicker values like 9-21-2026 with both libraries', () => {
|
|
41
|
+
expect(formatWithDayjs('9-21-2026', 'YYYY-MM-DD', 'MM-DD-YYYY')).toBe(
|
|
42
|
+
'2026-09-21',
|
|
43
|
+
);
|
|
44
|
+
expect(formatWithDateFns('9-21-2026', 'YYYY-MM-DD', 'MM-DD-YYYY')).toBe(
|
|
45
|
+
'2026-09-21',
|
|
46
|
+
);
|
|
47
|
+
expect(formatWithDayjs('9-5-2026', 'YYYY-MM-DD', 'MM-DD-YYYY')).toBe(
|
|
48
|
+
'2026-09-05',
|
|
49
|
+
);
|
|
50
|
+
expect(formatWithDateFns('9-5-2026', 'YYYY-MM-DD', 'MM-DD-YYYY')).toBe(
|
|
51
|
+
'2026-09-05',
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('dispatches to dayjs by default and to date-fns when useDateFns is true', () => {
|
|
56
|
+
expect(
|
|
57
|
+
formatDate('2025-01-10', 'MM-DD-YYYY', { parseFormat: 'YYYY-MM-DD' }),
|
|
58
|
+
).toBe('01-10-2025');
|
|
59
|
+
|
|
60
|
+
expect(
|
|
61
|
+
formatDate('2025-01-10', 'MM-DD-YYYY', {
|
|
62
|
+
parseFormat: 'YYYY-MM-DD',
|
|
63
|
+
useDateFns: true,
|
|
64
|
+
}),
|
|
65
|
+
).toBe('01-10-2025');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('formats Date objects with both libraries', () => {
|
|
69
|
+
const date = new Date(2025, 0, 10);
|
|
70
|
+
|
|
71
|
+
expect(formatWithDayjs(date, 'DDMMYYYY')).toBe('10012025');
|
|
72
|
+
expect(formatWithDateFns(date, 'DDMMYYYY')).toBe('10012025');
|
|
73
|
+
expect(formatDate(date, 'DDMMYYYY', { useDateFns: true })).toBe('10012025');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
format as dateFnsFormat,
|
|
3
|
+
isValid,
|
|
4
|
+
parse as dateFnsParse,
|
|
5
|
+
} from 'date-fns';
|
|
6
|
+
|
|
7
|
+
import dayjs from '@/utils/date';
|
|
8
|
+
|
|
9
|
+
export type DateInput = string | Date;
|
|
10
|
+
|
|
11
|
+
export type FormatDateOptions = {
|
|
12
|
+
parseFormat?: string;
|
|
13
|
+
useDateFns?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function toDateFnsFormatPattern(dayjsPattern: string): string {
|
|
17
|
+
return dayjsPattern.replaceAll('YYYY', 'yyyy').replaceAll('DD', 'dd');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// DatePicker emits unpadded values like "9-21-2026". Padded tokens (MM/DD)
|
|
21
|
+
// fail to parse those in dayjs; unpadded tokens still accept "09-21-2026".
|
|
22
|
+
function toFlexibleDayjsParsePattern(dayjsPattern: string): string {
|
|
23
|
+
return dayjsPattern.replaceAll('DD', 'D').replaceAll('MM', 'M');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function toDateFnsParsePattern(dayjsPattern: string): string {
|
|
27
|
+
return toFlexibleDayjsParsePattern(dayjsPattern)
|
|
28
|
+
.replaceAll('YYYY', 'yyyy')
|
|
29
|
+
.replaceAll('D', 'd');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formatWithDayjs(
|
|
33
|
+
value: DateInput,
|
|
34
|
+
outputFormat: string,
|
|
35
|
+
parseFormat?: string,
|
|
36
|
+
): string {
|
|
37
|
+
const parsed =
|
|
38
|
+
parseFormat && typeof value === 'string'
|
|
39
|
+
? dayjs(value, toFlexibleDayjsParsePattern(parseFormat))
|
|
40
|
+
: dayjs(value);
|
|
41
|
+
return parsed.format(outputFormat);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function formatWithDateFns(
|
|
45
|
+
value: DateInput,
|
|
46
|
+
outputFormat: string,
|
|
47
|
+
parseFormat?: string,
|
|
48
|
+
): string {
|
|
49
|
+
let date: Date;
|
|
50
|
+
|
|
51
|
+
if (value instanceof Date) {
|
|
52
|
+
date = value;
|
|
53
|
+
} else if (parseFormat) {
|
|
54
|
+
date = dateFnsParse(value, toDateFnsParsePattern(parseFormat), new Date());
|
|
55
|
+
} else {
|
|
56
|
+
date = new Date(value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!isValid(date)) {
|
|
60
|
+
return 'Invalid Date';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return dateFnsFormat(date, toDateFnsFormatPattern(outputFormat));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function formatDate(
|
|
67
|
+
value: DateInput,
|
|
68
|
+
outputFormat: string,
|
|
69
|
+
options: FormatDateOptions = {},
|
|
70
|
+
): string {
|
|
71
|
+
const { parseFormat, useDateFns = false } = options;
|
|
72
|
+
|
|
73
|
+
return useDateFns
|
|
74
|
+
? formatWithDateFns(value, outputFormat, parseFormat)
|
|
75
|
+
: formatWithDayjs(value, outputFormat, parseFormat);
|
|
76
|
+
}
|