Skip to content
This repository was archived by the owner on Apr 27, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/components/shared/forms/DateInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<template>
<div class="ui input" :class="{error: error}">
<input type="date" v-model="date" :min="minDate" :max="maxDate"/>
</div>
</template>

<script>
import moment from 'moment'

/**
* Date input
*
* @example ./croud-date-input.md
*/
export default {
name: 'croud-date-input',

props: {
/**
* Alias for v-model, value of the date input as a moment object or an iso string
*/
value: {
type: [Object, String],
required: true,
},

/**
* Minimum date as a moment object or an iso string
*/
min: {
type: [Object, String],
},

/**
* Maximum date as a moment object or an iso string
*/
max: {
type: [Object, String],
},
},

data() {
return {
format: 'YYYY-MM-DD',
error: false,
}
},

computed: {
date: {
get() {
const date = moment(this.value)
return date.isValid() ? moment(this.value).format(this.format) : this.value
},
set(val) {
const date = moment(val, this.format, true)

if (!date.isValid()) {
this.$emit('invalid-date', date)
this.error = true
} else if ((this.max && date.isAfter(moment(this.max), 'd'))
|| (this.min && date.isBefore(moment(this.min), 'd'))) {
this.$emit('validation-error', date)
this.error = true
} else {
this.error = false
}

this.$emit('input', date.isValid() ? date : val)
},
},

minDate() {
return this.min ? moment(this.min).format(this.format) : null
},

maxDate() {
return this.max ? moment(this.max).format(this.format) : null
},
},
}
</script>
14 changes: 14 additions & 0 deletions src/components/shared/forms/croud-date-input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
### Basic usage
Pass through a moment object or an iso string to set the initial value

<croud-date-input v-model="today"/>

### Invalid date
This component will emit the **invalid-date** event if the date input is cleared down or if moment can't parse the date from the input

<croud-date-input v-model="today" @invalid-date="$toasted.error('Invalid date')"/>

### Validation
You can use the **min** and **max** props to set the limits of the date input. This is usually handled by the html5 input, but this component will emit a **validation-error** event if the date selected falls outside of the min and max values

<croud-date-input v-model="today" :min="tomorrow" :max="tomorrow" @validation-error="$toasted.error('Failed validation')"/>
100 changes: 100 additions & 0 deletions test/unit/forms/DateInput.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Vue from 'vue'
import moment from 'moment'
import DateInput from '../../../src/components/shared/forms/DateInput'

const Constructor = Vue.extend(DateInput)

const vm = new Constructor({
propsData: {
value: moment(),
},
}).$mount()

const input = jest.fn()
const invalid = jest.fn()
const validation = jest.fn()
vm.$on('input', input)
vm.$on('invalid-date', invalid)
vm.$on('validation-error', validation)

describe('Date Input', () => {
it('should match the snapshot', () => {
expect(vm.$el).toMatchSnapshot()
})

describe('events', () => {
beforeEach(() => {
input.mockReset()
invalid.mockReset()
validation.mockReset()
})

it('shouldn\'t be in an error state by default', () => {
expect(vm.error).toBe(false)
})

it('should fire input event when date changes', (done) => {
vm.date = moment().add(1, 'd')
vm.$nextTick(() => {
expect(input).toBeCalled()
done()
})
})

describe('invalid date', () => {
it('should fire invalid-date event when date is cleared', (done) => {
vm.date = ''
vm.$nextTick(() => {
expect(invalid).toBeCalled()
done()
})
})

it('should notice an invalid date and add error class', (done) => {
vm.date = '2018-04-31'
vm.$nextTick(() => {
expect(invalid).toBeCalled()
expect(vm.error).toBe(true)
done()
})
})
})

describe('validation', () => {
it('should fire validation-error event if sooner than min date', (done) => {
vm.min = moment().add(1, 'd')
vm.max = null
vm.date = moment()
vm.$nextTick(() => {
expect(validation).toBeCalled()
expect(vm.error).toBe(true)
done()
})
})

it('should fire validation-error event if later than max date', (done) => {
vm.min = null
vm.max = moment().subtract(1, 'd')
vm.date = moment()

vm.$nextTick(() => {
expect(validation).toBeCalled()
expect(vm.error).toBe(true)
done()
})
})

it('should not fire validation-error if between min and max', (done) => {
vm.min = moment().subtract(1, 'd')
vm.max = moment().add(1, 'd')
vm.date = moment()

vm.$nextTick(() => {
expect(validation).not.toBeCalled()
expect(vm.error).toBe(false)
done()
})
})
})
})
})
11 changes: 11 additions & 0 deletions test/unit/forms/__snapshots__/DateInput.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Date Input should match the snapshot 1`] = `
<div
class="ui input"
>
<input
type="date"
/>
</div>
`;