1<template>
2  <b-row class="mb-2">
3    <b-col class="d-sm-flex">
4      <b-form-group
5        :label="$t('global.table.fromDate')"
6        label-for="input-from-date"
7        class="mr-3 my-0 w-100"
8      >
9        <b-input-group>
10          <b-form-input
11            id="input-from-date"
12            v-model="fromDate"
13            placeholder="YYYY-MM-DD"
14            :state="getValidationState($v.fromDate)"
15            class="form-control-with-button mb-3 mb-md-0"
16            @blur="$v.fromDate.$touch()"
17          />
18          <b-form-invalid-feedback role="alert">
19            <template v-if="!$v.fromDate.pattern">
20              {{ $t('global.form.invalidFormat') }}
21            </template>
22            <template v-if="!$v.fromDate.maxDate">
23              {{ $t('global.form.dateMustBeBefore', { date: toDate }) }}
24            </template>
25          </b-form-invalid-feedback>
26          <b-form-datepicker
27            v-model="fromDate"
28            class="btn-datepicker btn-icon-only"
29            button-only
30            right
31            :max="toDate"
32            :hide-header="true"
33            :locale="locale"
34            :label-help="
35              $t('global.calendar.useCursorKeysToNavigateCalendarDates')
36            "
37            :title="$t('global.calendar.selectDate')"
38            button-variant="link"
39            aria-controls="input-from-date"
40          >
41            <template #button-content>
42              <icon-calendar />
43              <span class="sr-only">
44                {{ $t('global.calendar.selectDate') }}
45              </span>
46            </template>
47          </b-form-datepicker>
48        </b-input-group>
49      </b-form-group>
50      <b-form-group
51        :label="$t('global.table.toDate')"
52        label-for="input-to-date"
53        class="my-0 w-100"
54      >
55        <b-input-group>
56          <b-form-input
57            id="input-to-date"
58            v-model="toDate"
59            placeholder="YYYY-MM-DD"
60            :state="getValidationState($v.toDate)"
61            class="form-control-with-button"
62            @blur="$v.toDate.$touch()"
63          />
64          <b-form-invalid-feedback role="alert">
65            <template v-if="!$v.toDate.pattern">
66              {{ $t('global.form.invalidFormat') }}
67            </template>
68            <template v-if="!$v.toDate.minDate">
69              {{ $t('global.form.dateMustBeAfter', { date: fromDate }) }}
70            </template>
71          </b-form-invalid-feedback>
72          <b-form-datepicker
73            v-model="toDate"
74            class="btn-datepicker btn-icon-only"
75            button-only
76            right
77            :min="fromDate"
78            :hide-header="true"
79            :locale="locale"
80            :label-help="
81              $t('global.calendar.useCursorKeysToNavigateCalendarDates')
82            "
83            :title="$t('global.calendar.selectDate')"
84            button-variant="link"
85            aria-controls="input-to-date"
86          >
87            <template #button-content>
88              <icon-calendar />
89              <span class="sr-only">
90                {{ $t('global.calendar.selectDate') }}
91              </span>
92            </template>
93          </b-form-datepicker>
94        </b-input-group>
95      </b-form-group>
96    </b-col>
97  </b-row>
98</template>
99
100<script>
101import IconCalendar from '@carbon/icons-vue/es/calendar/20';
102import { helpers } from 'vuelidate/lib/validators';
103
104import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
105
106const isoDateRegex = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/;
107
108export default {
109  components: { IconCalendar },
110  mixins: [VuelidateMixin],
111  data() {
112    return {
113      fromDate: '',
114      toDate: '',
115      offsetToDate: '',
116      locale: this.$store.getters['global/languagePreference'],
117    };
118  },
119  validations() {
120    return {
121      fromDate: {
122        pattern: helpers.regex('pattern', isoDateRegex),
123        maxDate: (value) => {
124          if (!this.toDate) return true;
125          const date = new Date(value);
126          const maxDate = new Date(this.toDate);
127          if (date.getTime() > maxDate.getTime()) return false;
128          return true;
129        },
130      },
131      toDate: {
132        pattern: helpers.regex('pattern', isoDateRegex),
133        minDate: (value) => {
134          if (!this.fromDate) return true;
135          const date = new Date(value);
136          const minDate = new Date(this.fromDate);
137          if (date.getTime() < minDate.getTime()) return false;
138          return true;
139        },
140      },
141    };
142  },
143  watch: {
144    fromDate() {
145      this.emitChange();
146    },
147    toDate(newVal) {
148      // Offset the end date to end of day to make sure all
149      // entries from selected end date are included in filter
150      this.offsetToDate = new Date(newVal).setUTCHours(23, 59, 59, 999);
151      this.emitChange();
152    },
153  },
154  methods: {
155    emitChange() {
156      if (this.$v.$invalid) return;
157      this.$v.$reset(); //reset to re-validate on blur
158      this.$emit('change', {
159        fromDate: this.fromDate ? new Date(this.fromDate) : null,
160        toDate: this.toDate ? new Date(this.offsetToDate) : null,
161      });
162    },
163  },
164};
165</script>
166