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