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