From 0e641a906401f3ee859fc3143f0d73571e21888d Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Mon, 23 Sep 2019 15:27:09 -0400 Subject: [PATCH 01/20] Create vue component to manage date range logic --- js/components/clin_fields.js | 2 + js/components/pop_date_range.js | 30 ++++ js/index.js | 2 + templates/components/clin_fields.html | 144 +---------------- templates/components/pop_date_range.html | 192 +++++++++++++++++++++++ 5 files changed, 229 insertions(+), 141 deletions(-) create mode 100644 js/components/pop_date_range.js create mode 100644 templates/components/pop_date_range.html diff --git a/js/components/clin_fields.js b/js/components/clin_fields.js index 0678e111..03102025 100644 --- a/js/components/clin_fields.js +++ b/js/components/clin_fields.js @@ -7,6 +7,7 @@ import Modal from '../mixins/modal' import optionsinput from './options_input' import textinput from './text_input' import clindollaramount from './clin_dollar_amount' +import PopDateRange from './pop_date_range' const TOTAL_AMOUNT = 'total_amount' const OBLIGATED_AMOUNT = 'obligated_amount' @@ -23,6 +24,7 @@ export default { optionsinput, textinput, clindollaramount, + PopDateRange, }, mixins: [Modal], diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js new file mode 100644 index 00000000..97d4b097 --- /dev/null +++ b/js/components/pop_date_range.js @@ -0,0 +1,30 @@ +import DateSelector from './date_selector' + +export default { + name: 'pop-date-range', + + components: { + DateSelector, + }, + + props: { + initialMinStartDate: String, + initialMaxEndDate: String, + initialStartDate: String, + initialEndDate: String, + clinIndex: Number, + }, + + data: function() { + return { + startDate: this.initialStartDate, + endDate: this.initialEndDate, + startValid: false, + endValid: false, + minStartDate: this.initialMinStartDate, + maxStartDate: this.initialMaxEndDate, + minEndDate: this.initialMinStartDate, + maxEndDate: this.initialMaxEndDate, + } + }, +} diff --git a/js/index.js b/js/index.js index 0a3db6ba..575006d4 100644 --- a/js/index.js +++ b/js/index.js @@ -32,6 +32,7 @@ import NewEnvironment from './components/forms/new_environment' import SemiCollapsibleText from './components/semi_collapsible_text' import ToForm from './components/forms/to_form' import ClinFields from './components/clin_fields' +import PopDateRange from './components/pop_date_range' Vue.config.productionTip = false @@ -65,6 +66,7 @@ const app = new Vue({ SemiCollapsibleText, ToForm, ClinFields, + PopDateRange, }, mounted: function() { diff --git a/templates/components/clin_fields.html b/templates/components/clin_fields.html index 82e54a8e..b6db59f3 100644 --- a/templates/components/clin_fields.html +++ b/templates/components/clin_fields.html @@ -4,6 +4,7 @@ {% from 'components/icon.html' import Icon %} {% from 'components/options_input.html' import OptionsInput %} {% from 'components/text_input.html' import TextInput %} +{% from 'components/pop_date_range.html' import PopDateRange %} {% macro CLINFields(contract_start, contract_end, fields=None, index=None) %} {% set contract_end_formatted = contract_end | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") %} {% if fields %} -
-
- {{ DatePicker(fields.start_date, watch=True, optional=False) }} -
-
-
-
- {% call DatePicker(fields.end_date, watch=True, optional=False) %} - {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': contract_end_formatted})) }} - {% endcall %} -
-
+ {{ PopDateRange(start_field=fields.start_date, end_field=fields.end_date, watch=True, optional=False, mindate=contract_start | dateFromString(formatter="%Y-%m-%d"), maxdate=contract_end | dateFromString(formatter="%Y-%m-%d")) }} {% else %} -
-
- -
- -
- {{ 'task_orders.form.pop_start' | translate }} -
-

- {{ 'task_orders.form.pop_example' | translate }} -

-
- -
- - -
- - -
- -
- - -
- -
- - -
- -
- {{ Icon("ok", classes="icon--green") }} -
-
-
-
-
-
-
-
- -
- -
- {{ 'task_orders.form.pop_end' | translate }} -
- - {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': contract_end_formatted})) }} - -

- {{ 'task_orders.form.pop_example' | translate }} -

-
- -
- - -
- - -
- -
- - -
- -
- - -
- -
- {{ Icon("ok", classes="icon--green") }} -
-
-
-
-
-
+ {{ PopDateRange(watch=True, optional=False, mindate=contract_start | dateFromString(formatter="%Y-%m-%d"), maxdate=contract_end | dateFromString(formatter="%Y-%m-%d")) }} {% endif %}
diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html new file mode 100644 index 00000000..a468b8fa --- /dev/null +++ b/templates/components/pop_date_range.html @@ -0,0 +1,192 @@ +{% from 'components/alert.html' import Alert %} +{% from 'components/icon.html' import Icon %} + +{% macro PopDateRange(start_field=None, end_field=None, mindate=mindate, maxdate=maxdate, watch=False, optional=True) %} + + +
+
+
+ + +
+ +
+ {{ "task_orders.form.pop_start" | translate }} +
+ +

+ {{ "task_orders.form.pop_example" | translate | safe }} +

+
+ +
+ + +
+ + +
+ +
+ + +
+ +
+ + + +
+ +
+
+ {{ Icon("ok", classes="icon--green") }} +
+
+ {{ Icon("alert", classes="icon--red")}} +
+
+
+
+
+
+
+ +
+
+ + +
+ +
+ {{ 'task_orders.form.pop_end' | translate }} +
+ + {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': contract_end_formatted})) }} + +

+ {{ 'task_orders.form.pop_example' | translate }} +

+
+ +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ {{ Icon("ok", classes="icon--green") }} +
+
+ {{ Icon("alert", classes="icon--red")}} +
+
+
+
+
+
+
+
+
+{% endmacro %} From d42cd1ff4f7578d3cc1785306de95b7f6739387e Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Mon, 23 Sep 2019 16:37:39 -0400 Subject: [PATCH 02/20] Dynamically update the max and min values for start and end date based on the date in the other field and contract dates --- .secrets.baseline | 2 +- js/components/pop_date_range.js | 57 +++++++++++++++++++++--- templates/components/pop_date_range.html | 10 ++--- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 3acc6dd6..e40d679e 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -199,5 +199,5 @@ } ] }, - "version": "0.12.6" + "version": "0.12.5" } diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 97d4b097..4e19e128 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -1,5 +1,10 @@ +import { format } from 'date-fns' + import DateSelector from './date_selector' +const START_DATE = 'start_date' +const END_DATE = 'end_date' + export default { name: 'pop-date-range', @@ -17,14 +22,54 @@ export default { data: function() { return { - startDate: this.initialStartDate, - endDate: this.initialEndDate, + startDate: new Date(this.initialStartDate), + endDate: new Date(this.initialEndDate), startValid: false, endValid: false, - minStartDate: this.initialMinStartDate, - maxStartDate: this.initialMaxEndDate, - minEndDate: this.initialMinStartDate, - maxEndDate: this.initialMaxEndDate, + minStartDate: new Date(this.initialMinStartDate), + maxEndDate: new Date(this.initialMaxEndDate), } }, + + mounted: function() { + this.$root.$on('field-change', this.handleDateChange) + }, + + methods: { + handleDateChange: function(event) { + if (event.name.includes(START_DATE)) { + if (!!event.value) this.startDate = new Date(event.value) + if (!!event.valid) this.startValid = event.valid + } else if (event.name.includes(END_DATE)) { + if (!!event.value) this.endDate = new Date(event.value) + if (!!event.valid) this.endValid = event.valid + } + }, + + maxStartDate: function() { + if (this.endDate < new Date(this.initialMaxEndDate)) { + return this.endDate + } else { + return this.initialMaxEndDate + } + }, + + minEndDate: function() { + if (this.startDate > new Date(this.initialMinStartDate)) { + return this.startDate + } else { + return this.initialMinEndDate + } + }, + }, + + computed: { + maxStartProp: function() { + return format(this.maxStartDate(), 'YYYY-MM-DD') + }, + + minEndProp: function() { + return format(this.minEndDate(), 'YYYY-MM-DD') + } + } } diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index a468b8fa..ad1c3fcd 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -18,8 +18,8 @@
-
+
{{ Icon("ok", classes="icon--green") }}
From d52abeb0a949854946bfc97351faf36d1601366f Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Mon, 23 Sep 2019 16:52:05 -0400 Subject: [PATCH 03/20] Only update the min and max values for other field when the field that was updated is valid -- This prevents both fields from becoming invalid when the dates are not in chronological order. --- js/components/pop_date_range.js | 43 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 4e19e128..837e671b 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -21,13 +21,20 @@ export default { }, data: function() { + var start = new Date(this.initialStartDate) + var end = new Date(this.initialEndDate) + var contractStart = new Date(this.initialMinStartDate) + var contractEnd = new Date(this.initialMaxEndDate) + return { - startDate: new Date(this.initialStartDate), - endDate: new Date(this.initialEndDate), + startDate: start, + endDate: end, startValid: false, endValid: false, - minStartDate: new Date(this.initialMinStartDate), - maxEndDate: new Date(this.initialMaxEndDate), + maxStartDate: this.calcMaxStartDate(end, contractEnd), + minEndDate: this.calcMinEndDate(start, contractStart), + contractStart: contractStart, + contractEnd: contractEnd, } }, @@ -40,36 +47,40 @@ export default { if (event.name.includes(START_DATE)) { if (!!event.value) this.startDate = new Date(event.value) if (!!event.valid) this.startValid = event.valid + if (this.startValid) + this.minEndDate = this.calcMinEndDate(this.startDate) } else if (event.name.includes(END_DATE)) { if (!!event.value) this.endDate = new Date(event.value) if (!!event.valid) this.endValid = event.valid + if (this.endValid) + this.maxStartDate = this.calcMaxStartDate(this.endDate) } }, - maxStartDate: function() { - if (this.endDate < new Date(this.initialMaxEndDate)) { - return this.endDate + calcMaxStartDate: function(date, end = this.contractEnd) { + if (date < end) { + return date } else { - return this.initialMaxEndDate + return end } }, - minEndDate: function() { - if (this.startDate > new Date(this.initialMinStartDate)) { - return this.startDate + calcMinEndDate: function(date, start = this.contractStart) { + if (date > start) { + return date } else { - return this.initialMinEndDate + return start } }, }, computed: { maxStartProp: function() { - return format(this.maxStartDate(), 'YYYY-MM-DD') + return format(this.maxStartDate, 'YYYY-MM-DD') }, minEndProp: function() { - return format(this.minEndDate(), 'YYYY-MM-DD') - } - } + return format(this.minEndDate, 'YYYY-MM-DD') + }, + }, } From 843501c00aa043cdc7d0770e5c2f75d673132cc3 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 24 Sep 2019 09:59:50 -0400 Subject: [PATCH 04/20] Fix bug where name attribute of start date fields was not properly assigned Fix bug in pop_date_range were startValid and endValid were not being properly updated --- js/components/pop_date_range.js | 10 ++++++---- templates/components/pop_date_range.html | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 837e671b..2ec369f6 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -46,14 +46,16 @@ export default { handleDateChange: function(event) { if (event.name.includes(START_DATE)) { if (!!event.value) this.startDate = new Date(event.value) - if (!!event.valid) this.startValid = event.valid - if (this.startValid) + if (event.valid != undefined) this.startValid = event.valid + if (this.startValid) { this.minEndDate = this.calcMinEndDate(this.startDate) + } } else if (event.name.includes(END_DATE)) { if (!!event.value) this.endDate = new Date(event.value) - if (!!event.valid) this.endValid = event.valid - if (this.endValid) + if (event.valid != undefined) this.endValid = event.valid + if (this.endValid) { this.maxStartDate = this.calcMaxStartDate(this.endDate) + } } }, diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index ad1c3fcd..bdc32830 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -44,7 +44,7 @@
- +
From 32583feb991aa5c75abde4e8864cb4520fe477ad Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 24 Sep 2019 10:51:36 -0400 Subject: [PATCH 05/20] Validate year based on min and max dates and only show the validation icons when the date has been completely filled in --- js/components/date_selector.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index 646cc6c5..8ca56cb0 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -102,7 +102,9 @@ export default { isYearValid: function() { // Emit a change event - var valid = parseInt(this.year) >= 1 + var minYear = new Date(this.mindate).getFullYear() + var maxYear = new Date(this.maxdate).getFullYear() + var valid = this.year >= minYear && this.year <= maxYear this._emitChange('year', this.year, valid) return valid }, @@ -135,6 +137,15 @@ export default { ) }, + isDateComplete: function() { + return ( + !!this.day && + !!this.month && + !!this.year && + this.year > 999 + ) + }, + daysMaxCalculation: function() { switch (parseInt(this.month)) { case 2: // February @@ -161,7 +172,7 @@ export default { methods: { onInput: function(e) { - this.showValidation = true + if (this.isDateComplete) this.showValidation = true emitEvent('field-change', this, { value: this.formattedDate, From e26edcd1bb68d24583486a1995fc8bbabb61d2a2 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 24 Sep 2019 13:08:29 -0400 Subject: [PATCH 06/20] Add tests for updated functionality in date-selector and formatting --- js/components/__tests__/date_selector.test.js | 30 +++++++++++++++++++ js/components/date_selector.js | 20 +++++++------ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/js/components/__tests__/date_selector.test.js b/js/components/__tests__/date_selector.test.js index 61bb9dfe..70125c9d 100644 --- a/js/components/__tests__/date_selector.test.js +++ b/js/components/__tests__/date_selector.test.js @@ -163,6 +163,20 @@ describe('DateSelector', () => { component.year = new Date().getFullYear() expect(component.isYearValid).toEqual(true) }) + + it('returns true when year is between min and max years', () => { + component.year = new Date('2019-01-01').getFullYear() + component.mindate = new Date('2018-01-01') + component.maxdate = new Date('2019-12-31') + expect(component.isYearValid).toEqual(true) + }) + + it('returns false when year is outside of min and max years', () => { + component.year = new Date('2020-01-01').getFullYear() + component.mindate = new Date('2018-01-01') + component.maxdate = new Date('2019-01-01') + expect(component.isYearValid).toEqual(false) + }) }) describe('formattedDate', () => { @@ -184,4 +198,20 @@ describe('DateSelector', () => { expect(component.formattedDate).toEqual('01/22/1988') }) }) + + describe('isDateComplete', () => { + it('returns true if all fields are completed', () => { + component.day = 22 + component.month = 1 + component.year = 1988 + expect(component.isDateComplete).toEqual(true) + }) + + it('returns false if all fields are not completed', () => { + component.day = 22 + component.month = 1 + component.year = 19 + expect(component.isDateComplete).toEqual(false) + }) + }) }) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index 8ca56cb0..0398de49 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -102,9 +102,16 @@ export default { isYearValid: function() { // Emit a change event - var minYear = new Date(this.mindate).getFullYear() - var maxYear = new Date(this.maxdate).getFullYear() - var valid = this.year >= minYear && this.year <= maxYear + var valid + var minYear = this.mindate ? new Date(this.mindate).getFullYear() : null + var maxYear = this.maxdate ? new Date(this.maxdate).getFullYear() : null + + if (minYear && maxYear) { + valid = this.year >= minYear && this.year <= maxYear + } else { + valid = parseInt(this.year) >= 1 + } + this._emitChange('year', this.year, valid) return valid }, @@ -138,12 +145,7 @@ export default { }, isDateComplete: function() { - return ( - !!this.day && - !!this.month && - !!this.year && - this.year > 999 - ) + return !!this.day && !!this.month && !!this.year && this.year > 999 }, daysMaxCalculation: function() { From 53cef32af56b937d7d12ce7987cdcd6886756deb Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 24 Sep 2019 14:18:21 -0400 Subject: [PATCH 07/20] Use date-selector component to display errors related to date fields --- js/components/__tests__/date_selector.test.js | 36 +++++++++++++++++++ js/components/date_selector.js | 16 +++++++++ templates/components/clin_fields.html | 5 --- templates/components/pop_date_range.html | 14 ++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/js/components/__tests__/date_selector.test.js b/js/components/__tests__/date_selector.test.js index 70125c9d..8820ea41 100644 --- a/js/components/__tests__/date_selector.test.js +++ b/js/components/__tests__/date_selector.test.js @@ -214,4 +214,40 @@ describe('DateSelector', () => { expect(component.isDateComplete).toEqual(false) }) }) + + describe('minError', () => { + it('returns true if the date is before mindate', () => { + component.mindate = new Date("2020-01-01") + component.day = 1 + component.month = 1 + component.year = 2000 + expect(component.minError).toEqual(true) + }) + + it('returns fals if the date is after mindate', () => { + component.mindate = new Date("2020-01-01") + component.day = 1 + component.month = 1 + component.year = 2025 + expect(component.minError).toEqual(false) + }) + }) + + describe('maxError', () => { + it('returns true if the date is after maxdate', () => { + component.maxdate = new Date("2020-01-01") + component.day = 1 + component.month = 1 + component.year = 2025 + expect(component.maxError).toEqual(true) + }) + + it('returns false if the date is before maxdate', () => { + component.maxdate = new Date("2020-01-01") + component.day = 1 + component.month = 1 + component.year = 2005 + expect(component.maxError).toEqual(false) + }) + }) }) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index 0398de49..b11a856e 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -170,6 +170,22 @@ export default { return 31 } }, + + minError: function() { + if (this.isDateComplete) { + return new Date(this.mindate) > new Date(this.formattedDate) + } + + return false + }, + + maxError: function() { + if (this.isDateComplete) { + return new Date(this.maxdate) < new Date(this.formattedDate) + } + + return false + }, }, methods: { diff --git a/templates/components/clin_fields.html b/templates/components/clin_fields.html index b6db59f3..88b1b478 100644 --- a/templates/components/clin_fields.html +++ b/templates/components/clin_fields.html @@ -135,11 +135,6 @@ {% else %} {{ PopDateRange(watch=True, optional=False, mindate=contract_start | dateFromString(formatter="%Y-%m-%d"), maxdate=contract_end | dateFromString(formatter="%Y-%m-%d")) }} {% endif %} -
-
-

-
-
diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index bdc32830..a7f18ba3 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -41,6 +41,13 @@

{{ "task_orders.form.pop_example" | translate | safe }}

+ +
+ PoP start date must be on or after {{ mindate | formattedDate(formatter="%B %d, %Y") }}. +
+
+ PoP start date must be before end date. +
@@ -130,6 +137,13 @@

{{ 'task_orders.form.pop_example' | translate }}

+ +
+ PoP end date must be after start date. +
+
+ PoP end date must be on or after {{ maxdate | formattedDate(formatter="%B %d, %Y") }}. +
From eef15f311f142020a2b9098d4e4430f06cfb2a0e Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 24 Sep 2019 14:34:05 -0400 Subject: [PATCH 08/20] Remove logic for validating PoP date range out of clin-fields vue component --- js/components/clin_fields.js | 118 ----------------------------------- 1 file changed, 118 deletions(-) diff --git a/js/components/clin_fields.js b/js/components/clin_fields.js index 03102025..00ca9c45 100644 --- a/js/components/clin_fields.js +++ b/js/components/clin_fields.js @@ -1,7 +1,3 @@ -import * as R from 'ramda' -import { format } from 'date-fns' - -import DateSelector from './date_selector' import { emitEvent } from '../lib/emitters' import Modal from '../mixins/modal' import optionsinput from './options_input' @@ -11,16 +7,12 @@ import PopDateRange from './pop_date_range' const TOTAL_AMOUNT = 'total_amount' const OBLIGATED_AMOUNT = 'obligated_amount' -const START_DATE = 'start_date' -const END_DATE = 'end_date' -const POP = 'period_of_performance' const NUMBER = 'number' export default { name: 'clin-fields', components: { - DateSelector, optionsinput, textinput, clindollaramount, @@ -39,79 +31,26 @@ export default { type: Number, default: 0, }, - initialStartDate: { - type: String, - default: null, - }, - initialEndDate: { - type: String, - default: null, - }, initialClinNumber: { type: String, default: null, }, - contractStart: { - type: String, - required: true, - }, - contractEnd: { - type: String, - required: true, - }, }, data: function() { - const start = !!this.initialStartDate - ? new Date(this.initialStartDate) - : undefined - const end = !!this.initialEndDate - ? new Date(this.initialEndDate) - : undefined const fundingValidation = this.initialObligated && this.initialTotal ? this.initialObligated <= this.initialTotal : true - const popValidation = !this.initialStartDate ? false : start < end const clinNumber = !!this.initialClinNumber ? this.initialClinNumber : undefined - const contractStartDate = new Date(this.contractStart) - const contractEndDate = new Date(this.contractEnd) return { clinIndex: this.initialClinIndex, clinNumber: clinNumber, - startDate: start, - endDate: end, - popValid: popValidation, - startDateValid: false, - endDateValid: false, - contractStartDate: contractStartDate, - contractEndDate: contractEndDate, clinNumber: clinNumber, showClin: true, - popErrors: [], - validations: [ - { - func: this.popDateOrder, - message: 'PoP start date must be before end date.', - }, - { - func: this.popStartsAfterContract, - message: `PoP start date must be on or after ${format( - contractStartDate, - 'MMM D, YYYY' - )}.`, - }, - { - func: this.popEndsBeforeContract, - message: `PoP end date must be before or on ${format( - contractEndDate, - 'MMM D, YYYY' - )}.`, - }, - ], totalAmount: this.initialTotal || 0, obligatedAmount: this.initialObligated || 0, fundingValid: fundingValidation, @@ -129,11 +68,6 @@ export default { obligatedAmount: this.initialObligated, totalAmount: this.initialTotal, }) - emitEvent('field-mount', this, { - optional: false, - name: 'clins-' + this.clinIndex + '-' + POP, - valid: this.checkPopValid(), - }) }, methods: { @@ -145,50 +79,6 @@ export default { }) }, - checkPopValid: function() { - return ( - this.popDateOrder() && - this.popStartsAfterContract() && - this.popEndsBeforeContract() - ) - }, - - validatePop: function() { - this.popValid = this.checkPopValid() - emitEvent('field-change', this, { - name: 'clins-' + this.clinIndex + '-' + POP, - valid: this.popValid, - }) - - this.popErrors = R.pipe( - R.map(validation => - !validation.func() ? validation.message : undefined - ), - R.filter(Boolean) - )(this.validations) - }, - - popStartsAfterContract: function() { - if (this.startDateValid) { - return this.startDate >= this.contractStartDate - } - return true - }, - - popEndsBeforeContract: function() { - if (this.endDateValid) { - return this.endDate <= this.contractEndDate - } - return true - }, - - popDateOrder: function() { - if (!!this.startDate && !!this.endDate) { - return this.startDate < this.endDate - } - return true - }, - checkFundingValid: function() { return this.obligatedAmount <= this.totalAmount }, @@ -207,14 +97,6 @@ export default { } else if (event.name.includes(OBLIGATED_AMOUNT)) { this.obligatedAmount = parseFloat(event.value) this.validateFunding() - } else if (event.name.includes(START_DATE)) { - if (!!event.value) this.startDate = new Date(event.value) - if (!!event.valid) this.startDateValid = event.valid - this.validatePop() - } else if (event.name.includes(END_DATE)) { - if (!!event.value) this.endDate = new Date(event.value) - if (!!event.valid) this.endDateValid = event.valid - this.validatePop() } else if (event.name.includes(NUMBER)) { this.clinNumber = event.value } From 5e1ce65662884be7a785629bc484af0c1e1edba6 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 10:42:40 -0400 Subject: [PATCH 09/20] Move html out of clin fields macro and fix initial values in pop date range when there is no form data --- .secrets.baseline | 2 +- js/components/pop_date_range.js | 18 +- js/test_templates/clin_fields.html | 345 ++++++++++++----------- js/test_templates/to_form.html | 63 +++-- templates/components/clin_fields.html | 8 +- templates/components/pop_date_range.html | 18 +- 6 files changed, 256 insertions(+), 198 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index e40d679e..3acc6dd6 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -199,5 +199,5 @@ } ] }, - "version": "0.12.5" + "version": "0.12.6" } diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 2ec369f6..654ad4ed 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -15,14 +15,20 @@ export default { props: { initialMinStartDate: String, initialMaxEndDate: String, - initialStartDate: String, - initialEndDate: String, + initialStartDate: { + type: String, + default: null, + }, + initialEndDate: { + type: String, + default: null, + }, clinIndex: Number, }, data: function() { - var start = new Date(this.initialStartDate) - var end = new Date(this.initialEndDate) + var start = !!this.initialStartDate ? new Date(this.initialStartDate) : null + var end = !!this.initialEndDate ? new Date(this.initialEndDate) : null var contractStart = new Date(this.initialMinStartDate) var contractEnd = new Date(this.initialMaxEndDate) @@ -60,7 +66,7 @@ export default { }, calcMaxStartDate: function(date, end = this.contractEnd) { - if (date < end) { + if (!!date && date < end) { return date } else { return end @@ -68,7 +74,7 @@ export default { }, calcMinEndDate: function(date, start = this.contractStart) { - if (date > start) { + if (!!date && date > start) { return date } else { return start diff --git a/js/test_templates/clin_fields.html b/js/test_templates/clin_fields.html index e59aaa83..debfcad5 100644 --- a/js/test_templates/clin_fields.html +++ b/js/test_templates/clin_fields.html @@ -312,120 +312,143 @@
-
-
- - -
- -
- Start Date -
- + + - -

- For example: 07 04 1776 -

- -
- -
- - -
- - -
- -
- - -
- -
- - +
+
+ + v-bind:watch='true' + :optional='false' + inline-template> -
+
+ +
+ Start Date +
-
-
- +

+ For example: 07 04 1776 +

+ +
+ PoP start date must be on or after September 14, 2019. +
+
+ PoP start date must be before end date. +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+ + + +
+ +
+
+ -
-
- +
+
+ -
+
+
+
+
+
-
-
-
-
-
-
- -
- -
- End Date -
+
+
+ + +
+ +
+ End Date +
- - @@ -436,7 +459,7 @@

- A CLIN's period of performance must end before September 14, 2022. + A CLIN's period of performance must end before .

@@ -447,87 +470,85 @@
- - - -

- For example: 07 04 1776 -

- -
+

+ For example: 07 04 1776 +

-
- +
+ PoP end date must be after start date. +
+
+ PoP end date must be on or after September 14, 2022. +
+ -
- - -
+
+ -
- - -
+
+ + +
-
- - +
+ + +
-
+
+ + +
-
-
- +
+
+ -
-
- +
+
+ -
+
+
+
+
+
- - -
-
+
+ + -
-
-

-
-
diff --git a/js/test_templates/to_form.html b/js/test_templates/to_form.html index 817f7c5d..e2e30b07 100644 --- a/js/test_templates/to_form.html +++ b/js/test_templates/to_form.html @@ -199,17 +199,25 @@ Period of Performance
+ +
- -
+ +
- Start Date -
+ Start Date +

- For example: 07 04 1776 -

+ For example: 07 04 1776 +

+
+ PoP start date must be on or after September 14, 2019. +
+
+ PoP start date must be before end date. +
@@ -223,11 +231,19 @@
- +
+
+
+ +
+
@@ -235,22 +251,28 @@
- -
+ +
- End Date -
+ End Date +

- For example: 07 04 1776 -

+ For example: 07 04 1776 +

+
+ PoP end date must be after start date. +
+
+ PoP end date must be on or after September 14, 2022. +
@@ -266,19 +288,24 @@
+
+
+ +
+
-
-
-

-
+
- {% set contract_end_formatted = contract_end | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") %} + {% set contract_start_formatted = contract_start | dateFromString(formatter="%Y-%m-%d") %} + {% set contract_end_formatted = contract_end | dateFromString(formatter="%Y-%m-%d") %} {% if fields %} - {{ PopDateRange(start_field=fields.start_date, end_field=fields.end_date, watch=True, optional=False, mindate=contract_start | dateFromString(formatter="%Y-%m-%d"), maxdate=contract_end | dateFromString(formatter="%Y-%m-%d")) }} + {{ PopDateRange(start_field=fields.start_date, end_field=fields.end_date, watch=True, optional=False, mindate=contract_start, maxdate=contract_end) }} {% else %} - {{ PopDateRange(watch=True, optional=False, mindate=contract_start | dateFromString(formatter="%Y-%m-%d"), maxdate=contract_end | dateFromString(formatter="%Y-%m-%d")) }} + {{ PopDateRange(watch=True, optional=False, mindate=contract_start, maxdate=contract_end) }} {% endif %}
diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index a7f18ba3..a0a69a13 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -1,11 +1,15 @@ {% from 'components/alert.html' import Alert %} {% from 'components/icon.html' import Icon %} -{% macro PopDateRange(start_field=None, end_field=None, mindate=mindate, maxdate=maxdate, watch=False, optional=True) %} +{% macro PopDateRange(start_field=None, end_field=None, mindate=mindate, maxdate=maxdate, watch=False, optional=True, index=None) %}
- PoP start date must be on or after {{ mindate | formattedDate(formatter="%B %d, %Y") }}. + PoP start date must be on or after {{ mindate | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") }}.
PoP start date must be before end date. @@ -84,7 +88,7 @@
- PoP end date must be on or after {{ maxdate | formattedDate(formatter="%B %d, %Y") }}. + PoP end date must be on or after {{ maxdate | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") }}.
From 789e6662a2121d62faba7d13299fa55fa811be29 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 10:43:43 -0400 Subject: [PATCH 10/20] Add tests for pop date range vue component --- js/components/__tests__/date_selector.test.js | 8 +- .../__tests__/pop_date_range.test.js | 99 ++++++++ js/test_templates/clin_fields.html | 4 +- js/test_templates/pop_date_range.html | 234 ++++++++++++++++++ js/test_templates/to_form.html | 4 +- templates/components/pop_date_range.html | 4 +- tests/render_vue_component.py | 14 ++ 7 files changed, 357 insertions(+), 10 deletions(-) create mode 100644 js/components/__tests__/pop_date_range.test.js create mode 100644 js/test_templates/pop_date_range.html diff --git a/js/components/__tests__/date_selector.test.js b/js/components/__tests__/date_selector.test.js index 8820ea41..348a4726 100644 --- a/js/components/__tests__/date_selector.test.js +++ b/js/components/__tests__/date_selector.test.js @@ -217,7 +217,7 @@ describe('DateSelector', () => { describe('minError', () => { it('returns true if the date is before mindate', () => { - component.mindate = new Date("2020-01-01") + component.mindate = new Date('2020-01-01') component.day = 1 component.month = 1 component.year = 2000 @@ -225,7 +225,7 @@ describe('DateSelector', () => { }) it('returns fals if the date is after mindate', () => { - component.mindate = new Date("2020-01-01") + component.mindate = new Date('2020-01-01') component.day = 1 component.month = 1 component.year = 2025 @@ -235,7 +235,7 @@ describe('DateSelector', () => { describe('maxError', () => { it('returns true if the date is after maxdate', () => { - component.maxdate = new Date("2020-01-01") + component.maxdate = new Date('2020-01-01') component.day = 1 component.month = 1 component.year = 2025 @@ -243,7 +243,7 @@ describe('DateSelector', () => { }) it('returns false if the date is before maxdate', () => { - component.maxdate = new Date("2020-01-01") + component.maxdate = new Date('2020-01-01') component.day = 1 component.month = 1 component.year = 2005 diff --git a/js/components/__tests__/pop_date_range.test.js b/js/components/__tests__/pop_date_range.test.js new file mode 100644 index 00000000..661edb04 --- /dev/null +++ b/js/components/__tests__/pop_date_range.test.js @@ -0,0 +1,99 @@ +import Vue from 'vue' +import { mount } from '@vue/test-utils' + +import PopDateRange from '../pop_date_range' + +import { makeTestWrapper } from '../../test_utils/component_test_helpers' + +const PopDateRangeWrapper = makeTestWrapper({ + components: { PopDateRange }, + templatePath: 'pop_date_range.html', +}) + +describe('PopDateRange Test', () => { + const component = new Vue(PopDateRange) + + it('should calculate the max start date', () => { + component.contractEnd = new Date('2020-01-01') + const date = new Date('2019-12-31') + expect(component.calcMaxStartDate(date)).toEqual(date) + }) + + it('should calculate the min end date', () => { + component.contractStart = new Date('2020-01-01') + const date = new Date('2020-02-02') + expect(component.calcMinEndDate(date)).toEqual(date) + }) + + it('should add an error to the start date if it is out of range', () => { + const wrapper = mount(PopDateRangeWrapper, { + propsData: { + initialData: {}, + }, + }) + + const error = ['usa-input--error'] + var startDateField = wrapper.find('fieldset[name="start_date"]') + var endDateField = wrapper.find('fieldset[name="end_date"]') + + // set valid date range + startDateField.find('input[name="date-month"]').setValue('01') + startDateField.find('input[name="date-day"]').setValue('01') + startDateField.find('input[name="date-year"]').setValue('2020') + + endDateField.find('input[name="date-month"]').setValue('01') + endDateField.find('input[name="date-day"]').setValue('01') + endDateField.find('input[name="date-year"]').setValue('2021') + + // manually trigger the change event in the hidden fields + startDateField.find('input[name="start_date"]').trigger('change') + endDateField.find('input[name="end_date"]').trigger('change') + + // check that both dates do not have error class + expect(startDateField.classes()).toEqual(expect.not.arrayContaining(error)) + expect(endDateField.classes()).toEqual(expect.not.arrayContaining(error)) + + // update start date to be after end date and trigger change event + startDateField.find('input[name="date-year"]').setValue('2022') + startDateField.find('input[name="start_date"]').trigger('change') + + expect(startDateField.classes()).toEqual(expect.arrayContaining(error)) + expect(endDateField.classes()).toEqual(expect.not.arrayContaining(error)) + }) + + it('should add an error to the end date if it is out of range', () => { + const wrapper = mount(PopDateRangeWrapper, { + propsData: { + initialData: {}, + }, + }) + + const error = ['usa-input--error'] + var startDateField = wrapper.find('fieldset[name="start_date"]') + var endDateField = wrapper.find('fieldset[name="end_date"]') + + // set valid date range + startDateField.find('input[name="date-month"]').setValue('01') + startDateField.find('input[name="date-day"]').setValue('01') + startDateField.find('input[name="date-year"]').setValue('2020') + + endDateField.find('input[name="date-month"]').setValue('01') + endDateField.find('input[name="date-day"]').setValue('01') + endDateField.find('input[name="date-year"]').setValue('2021') + + // manually trigger the change event in the hidden fields + startDateField.find('input[name="start_date"]').trigger('change') + endDateField.find('input[name="end_date"]').trigger('change') + + // check that both dates do not have error class + expect(startDateField.classes()).toEqual(expect.not.arrayContaining(error)) + expect(endDateField.classes()).toEqual(expect.not.arrayContaining(error)) + + // update end date to be before end date and trigger change event + endDateField.find('input[name="date-year"]').setValue('2019') + endDateField.find('input[name="end_date"]').trigger('change') + + expect(startDateField.classes()).toEqual(expect.not.arrayContaining(error)) + expect(endDateField.classes()).toEqual(expect.arrayContaining(error)) + }) +}) diff --git a/js/test_templates/clin_fields.html b/js/test_templates/clin_fields.html index debfcad5..8ac3d44e 100644 --- a/js/test_templates/clin_fields.html +++ b/js/test_templates/clin_fields.html @@ -344,7 +344,7 @@ :optional='false' inline-template> -
+
Start Date @@ -443,7 +443,7 @@ :optional='false' inline-template> -
+
End Date diff --git a/js/test_templates/pop_date_range.html b/js/test_templates/pop_date_range.html new file mode 100644 index 00000000..d440fbec --- /dev/null +++ b/js/test_templates/pop_date_range.html @@ -0,0 +1,234 @@ + + + +
+
+
+ + +
+ +
+ Start Date +
+ +

+ For example: 07 04 1776 +

+ +
+ PoP start date must be on or after September 14, 2019. +
+
+ PoP start date must be before end date. +
+
+ +
+ + +
+ + +
+ +
+ + +
+ +
+ + + +
+ +
+
+ + + +
+
+ + + +
+
+
+
+
+
+
+ +
+
+ + +
+ +
+ End Date +
+ + + + + + +

+ For example: 07 04 1776 +

+ +
+ PoP end date must be after start date. +
+
+ PoP end date must be on or after September 14, 2022. +
+
+ +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + + +
+
+ + + +
+
+
+
+
+
+
+
+
diff --git a/js/test_templates/to_form.html b/js/test_templates/to_form.html index e2e30b07..1bbe8fbf 100644 --- a/js/test_templates/to_form.html +++ b/js/test_templates/to_form.html @@ -204,7 +204,7 @@
-
+
Start Date @@ -252,7 +252,7 @@
-
+
End Date diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index a0a69a13..a520b439 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -36,7 +36,7 @@ :optional='{{ optional | string | lower }}' inline-template> -
+
{{ "task_orders.form.pop_start" | translate }} @@ -130,7 +130,7 @@ :optional='{{ optional | string | lower }}' inline-template> -
+
{{ 'task_orders.form.pop_end' | translate }} diff --git a/tests/render_vue_component.py b/tests/render_vue_component.py index 3e9cd9c7..c4a7c135 100644 --- a/tests/render_vue_component.py +++ b/tests/render_vue_component.py @@ -135,3 +135,17 @@ def test_make_clin_fields(env, app): 0, ) write_template(clin_fields, "clin_fields.html") + + +def test_make_pop_date_range(env, app): + pop_date_range_template = env.get_template("components/pop_date_range.html") + pop_date_range_macro = getattr(pop_date_range_template.module, "PopDateRange") + form = CLINForm() + pop_date_range = pop_date_range_macro( + start_field=form.start_date, + end_field=form.end_date, + mindate=app.config.get("CONTRACT_START_DATE"), + maxdate=app.config.get("CONTRACT_END_DATE"), + index=1, + ) + write_template(pop_date_range, "pop_date_range.html") From e41aeaee2538dd9f3ae375e53097a109ef5398e3 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 13:58:30 -0400 Subject: [PATCH 11/20] Fix end date in alert --- templates/components/pop_date_range.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index a520b439..7fe1aab6 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -135,8 +135,8 @@
{{ 'task_orders.form.pop_end' | translate }}
- - {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': contract_end_formatted})) }} + {% set formatted_end_date = maxdate | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") %} + {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': formatted_end_date })) }}

{{ 'task_orders.form.pop_example' | translate }} From ad86dc33fc289b06fd406888e9131d6bdc9278e3 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 14:23:33 -0400 Subject: [PATCH 12/20] Show validation icon only if the date is complete --- js/components/date_selector.js | 3 --- js/test_templates/clin_fields.html | 12 ++++++------ js/test_templates/pop_date_range.html | 12 ++++++------ js/test_templates/to_form.html | 10 +++++----- templates/components/date_picker.html | 4 ++-- templates/components/pop_date_range.html | 8 ++++---- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index b11a856e..b12d4986 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -36,7 +36,6 @@ export default { month: this.initialmonth, year: this.initialyear, name: this.nameTag, - showValidation: false, } }, @@ -190,8 +189,6 @@ export default { methods: { onInput: function(e) { - if (this.isDateComplete) this.showValidation = true - emitEvent('field-change', this, { value: this.formattedDate, name: this.name, diff --git a/js/test_templates/clin_fields.html b/js/test_templates/clin_fields.html index 8ac3d44e..a4ffa8ad 100644 --- a/js/test_templates/clin_fields.html +++ b/js/test_templates/clin_fields.html @@ -344,7 +344,7 @@ :optional='false' inline-template> -

+
Start Date @@ -407,7 +407,7 @@
-
+
@@ -443,12 +443,12 @@ :optional='false' inline-template> -
+
End Date
- + @@ -459,7 +459,7 @@

- A CLIN's period of performance must end before . + A CLIN's period of performance must end before September 14, 2022.

@@ -525,7 +525,7 @@ />
-
+
diff --git a/js/test_templates/pop_date_range.html b/js/test_templates/pop_date_range.html index d440fbec..0852802d 100644 --- a/js/test_templates/pop_date_range.html +++ b/js/test_templates/pop_date_range.html @@ -29,7 +29,7 @@ :optional='true' inline-template> -
+
Start Date @@ -92,7 +92,7 @@
-
+
@@ -128,12 +128,12 @@ :optional='true' inline-template> -
+
End Date
- + @@ -144,7 +144,7 @@

- A CLIN's period of performance must end before . + A CLIN's period of performance must end before September 14, 2022.

@@ -210,7 +210,7 @@ />
-
+
diff --git a/js/test_templates/to_form.html b/js/test_templates/to_form.html index 1bbe8fbf..61e2e502 100644 --- a/js/test_templates/to_form.html +++ b/js/test_templates/to_form.html @@ -204,7 +204,7 @@
-
+
Start Date @@ -233,7 +233,7 @@
-
+
@@ -252,7 +252,7 @@
-
+
End Date @@ -260,7 +260,7 @@ @@ -288,7 +288,7 @@
-
+
diff --git a/templates/components/date_picker.html b/templates/components/date_picker.html index 9461f301..165eee64 100644 --- a/templates/components/date_picker.html +++ b/templates/components/date_picker.html @@ -21,7 +21,7 @@ :optional='{{ optional | string | lower }}' inline-template> -
+
{{ label }} @@ -83,7 +83,7 @@
-
+
{{ Icon("ok", classes="icon--green") }}
diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index 7fe1aab6..d5431916 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -36,7 +36,7 @@ :optional='{{ optional | string | lower }}' inline-template> -
+
{{ "task_orders.form.pop_start" | translate }} @@ -99,7 +99,7 @@
-
+
{{ Icon("ok", classes="icon--green") }}
@@ -130,7 +130,7 @@ :optional='{{ optional | string | lower }}' inline-template> -
+
{{ 'task_orders.form.pop_end' | translate }} @@ -192,7 +192,7 @@ />
-
+
{{ Icon("ok", classes="icon--green") }}
From c03820e53ad1360bfce1367191ec989e4a14bc07 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 15:58:04 -0400 Subject: [PATCH 13/20] Emit event on input from date selector so parent element can respond --- js/components/date_selector.js | 6 ++++++ js/components/pop_date_range.js | 4 ---- js/test_templates/clin_fields.html | 2 ++ js/test_templates/pop_date_range.html | 2 ++ js/test_templates/to_form.html | 4 ++-- templates/components/pop_date_range.html | 2 ++ 6 files changed, 14 insertions(+), 6 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index b12d4986..f0c83b12 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -195,6 +195,12 @@ export default { watch: this.watch, valid: this.isDateValid, }) + + this.$emit('date-change', { + value: this.formattedDate, + name: this.name, + valid: this.isDateValid, + }) }, _emitChange: function(name, value, valid) { diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 654ad4ed..54f54e65 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -44,10 +44,6 @@ export default { } }, - mounted: function() { - this.$root.$on('field-change', this.handleDateChange) - }, - methods: { handleDateChange: function(event) { if (event.name.includes(START_DATE)) { diff --git a/js/test_templates/clin_fields.html b/js/test_templates/clin_fields.html index a4ffa8ad..15d3027a 100644 --- a/js/test_templates/clin_fields.html +++ b/js/test_templates/clin_fields.html @@ -342,6 +342,7 @@ v-bind:watch='true' :optional='false' + v-on:date-change='handleDateChange' inline-template>
@@ -441,6 +442,7 @@ v-bind:watch='true' :optional='false' + v-on:date-change='handleDateChange' inline-template>
diff --git a/js/test_templates/pop_date_range.html b/js/test_templates/pop_date_range.html index 0852802d..1c70e5e9 100644 --- a/js/test_templates/pop_date_range.html +++ b/js/test_templates/pop_date_range.html @@ -27,6 +27,7 @@ v-bind:watch='false' :optional='true' + v-on:date-change='handleDateChange' inline-template>
@@ -126,6 +127,7 @@ v-bind:watch='false' :optional='true' + v-on:date-change='handleDateChange' inline-template>
diff --git a/js/test_templates/to_form.html b/js/test_templates/to_form.html index 61e2e502..6d091370 100644 --- a/js/test_templates/to_form.html +++ b/js/test_templates/to_form.html @@ -203,7 +203,7 @@
- +
@@ -251,7 +251,7 @@
- +
diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index d5431916..b4f6e540 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -34,6 +34,7 @@ {% endif %} v-bind:watch='{{ watch | string | lower }}' :optional='{{ optional | string | lower }}' + v-on:date-change='handleDateChange' inline-template>
@@ -128,6 +129,7 @@ {% endif %} v-bind:watch='{{ watch | string | lower }}' :optional='{{ optional | string | lower }}' + v-on:date-change='handleDateChange' inline-template>
From df5f4b9d3ef6057548186f1465c2e1fca8a9a0db Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 16:07:31 -0400 Subject: [PATCH 14/20] Get rid of unnecessary data in pop date range --- .../__tests__/pop_date_range.test.js | 4 ++-- js/components/pop_date_range.js | 24 +++++++------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/js/components/__tests__/pop_date_range.test.js b/js/components/__tests__/pop_date_range.test.js index 661edb04..ada35c15 100644 --- a/js/components/__tests__/pop_date_range.test.js +++ b/js/components/__tests__/pop_date_range.test.js @@ -14,13 +14,13 @@ describe('PopDateRange Test', () => { const component = new Vue(PopDateRange) it('should calculate the max start date', () => { - component.contractEnd = new Date('2020-01-01') + component.maxStartDate = new Date('2020-01-01') const date = new Date('2019-12-31') expect(component.calcMaxStartDate(date)).toEqual(date) }) it('should calculate the min end date', () => { - component.contractStart = new Date('2020-01-01') + component.minEndDate = new Date('2020-01-01') const date = new Date('2020-02-02') expect(component.calcMinEndDate(date)).toEqual(date) }) diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 54f54e65..52446593 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -33,35 +33,27 @@ export default { var contractEnd = new Date(this.initialMaxEndDate) return { - startDate: start, - endDate: end, - startValid: false, - endValid: false, maxStartDate: this.calcMaxStartDate(end, contractEnd), minEndDate: this.calcMinEndDate(start, contractStart), - contractStart: contractStart, - contractEnd: contractEnd, } }, methods: { handleDateChange: function(event) { if (event.name.includes(START_DATE)) { - if (!!event.value) this.startDate = new Date(event.value) - if (event.valid != undefined) this.startValid = event.valid - if (this.startValid) { - this.minEndDate = this.calcMinEndDate(this.startDate) + if (event.valid != undefined && event.valid) { + var date = new Date(event.value) + this.minEndDate = this.calcMinEndDate(date) } } else if (event.name.includes(END_DATE)) { - if (!!event.value) this.endDate = new Date(event.value) - if (event.valid != undefined) this.endValid = event.valid - if (this.endValid) { - this.maxStartDate = this.calcMaxStartDate(this.endDate) + if (event.valid != undefined && event.valid ) { + var date = new Date(event.value) + this.maxStartDate = this.calcMaxStartDate(date) } } }, - calcMaxStartDate: function(date, end = this.contractEnd) { + calcMaxStartDate: function(date, end = this.maxStartDate) { if (!!date && date < end) { return date } else { @@ -69,7 +61,7 @@ export default { } }, - calcMinEndDate: function(date, start = this.contractStart) { + calcMinEndDate: function(date, start = this.minEndDate) { if (!!date && date > start) { return date } else { From 92243965ec7f982e8c6e1809bc4436d1eb88a0d2 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Wed, 25 Sep 2019 16:30:53 -0400 Subject: [PATCH 15/20] parse contract dates into datetime objects --- atst/app.py | 7 +++++++ atst/forms/task_order.py | 9 ++------- js/components/pop_date_range.js | 2 +- templates/components/clin_fields.html | 2 -- templates/components/pop_date_range.html | 6 +++--- tests/forms/test_task_order.py | 8 ++------ 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/atst/app.py b/atst/app.py index 6a23abfe..f3e7276f 100644 --- a/atst/app.py +++ b/atst/app.py @@ -2,6 +2,7 @@ import os import re import pathlib from configparser import ConfigParser +from datetime import datetime from flask import Flask, request, g, session from flask_session import Session import redis @@ -175,6 +176,12 @@ def map_config(config): # with a Beat job once a day) "CELERY_RESULT_EXPIRES": 0, "CELERY_RESULT_EXTENDED": True, + "CONTRACT_START_DATE": datetime.strptime( + config.get("default", "CONTRACT_START_DATE"), "%Y-%m-%d" + ).date(), + "CONTRACT_END_DATE": datetime.strptime( + config.get("default", "CONTRACT_END_DATE"), "%Y-%m-%d" + ).date(), } diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index ddf029f8..fe764f27 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -9,7 +9,6 @@ from wtforms.fields import ( from wtforms.fields.html5 import DateField from wtforms.validators import Required, Optional, Length, NumberRange, ValidationError from flask_wtf import FlaskForm -from datetime import datetime from numbers import Number from .data import JEDI_CLIN_TYPES @@ -85,12 +84,8 @@ class CLINForm(FlaskForm): def validate(self, *args, **kwargs): valid = super().validate(*args, **kwargs) - contract_start = datetime.strptime( - app.config.get("CONTRACT_START_DATE"), "%Y-%m-%d" - ).date() - contract_end = datetime.strptime( - app.config.get("CONTRACT_END_DATE"), "%Y-%m-%d" - ).date() + contract_start = app.config.get("CONTRACT_START_DATE") + contract_end = app.config.get("CONTRACT_END_DATE") if ( self.start_date.data diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 52446593..7abac268 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -46,7 +46,7 @@ export default { this.minEndDate = this.calcMinEndDate(date) } } else if (event.name.includes(END_DATE)) { - if (event.valid != undefined && event.valid ) { + if (event.valid != undefined && event.valid) { var date = new Date(event.value) this.maxStartDate = this.calcMaxStartDate(date) } diff --git a/templates/components/clin_fields.html b/templates/components/clin_fields.html index 6c91d7fe..2baf6419 100644 --- a/templates/components/clin_fields.html +++ b/templates/components/clin_fields.html @@ -128,8 +128,6 @@ {{ 'task_orders.form.pop' | translate }}
- {% set contract_start_formatted = contract_start | dateFromString(formatter="%Y-%m-%d") %} - {% set contract_end_formatted = contract_end | dateFromString(formatter="%Y-%m-%d") %} {% if fields %} {{ PopDateRange(start_field=fields.start_date, end_field=fields.end_date, watch=True, optional=False, mindate=contract_start, maxdate=contract_end) }} {% else %} diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index b4f6e540..bde27736 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -48,7 +48,7 @@

- PoP start date must be on or after {{ mindate | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") }}. + PoP start date must be on or after {{ mindate | formattedDate(formatter="%B %d, %Y") }}.
PoP start date must be before end date. @@ -137,7 +137,7 @@
{{ 'task_orders.form.pop_end' | translate }}
- {% set formatted_end_date = maxdate | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") %} + {% set formatted_end_date = maxdate | formattedDate(formatter="%B %d, %Y") %} {{ Alert(message="task_orders.form.pop_end_alert" | translate({'end_date': formatted_end_date })) }}

@@ -148,7 +148,7 @@ PoP end date must be after start date.

- PoP end date must be on or after {{ maxdate | dateFromString(formatter="%Y-%m-%d") | formattedDate(formatter="%B %d, %Y") }}. + PoP end date must be on or after {{ formatted_end_date }}.
diff --git a/tests/forms/test_task_order.py b/tests/forms/test_task_order.py index 9fb12bcf..85a7c6af 100644 --- a/tests/forms/test_task_order.py +++ b/tests/forms/test_task_order.py @@ -38,12 +38,8 @@ def test_clin_form_start_date_before_end_date(): def test_clin_form_pop_dates_within_contract_dates(): - CONTRACT_START_DATE = datetime.datetime.strptime( - app.config.get("CONTRACT_START_DATE"), "%Y-%m-%d" - ).date() - CONTRACT_END_DATE = datetime.datetime.strptime( - app.config.get("CONTRACT_END_DATE"), "%Y-%m-%d" - ).date() + CONTRACT_START_DATE = app.config.get("CONTRACT_START_DATE") + CONTRACT_END_DATE = app.config.get("CONTRACT_END_DATE") invalid_start = CONTRACT_START_DATE - relativedelta(months=1) invalid_end = CONTRACT_END_DATE + relativedelta(months=1) From f840bbb941a0202293a0ec7f594146b23bf5071e Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 26 Sep 2019 13:18:38 -0400 Subject: [PATCH 16/20] Use let instead of var --- js/components/date_selector.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index f0c83b12..f6273231 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -2,7 +2,7 @@ import Vue from 'vue' import { getDaysInMonth } from 'date-fns' import { emitEvent } from '../lib/emitters' -var paddedNumber = function(number) { +let paddedNumber = function(number) { if ((number + '').length === 1) { return `0${number}` } else { @@ -86,24 +86,24 @@ export default { }, isMonthValid: function() { - var _month = parseInt(this.month) - var valid = _month >= 0 && _month <= 12 + let _month = parseInt(this.month) + let valid = _month >= 0 && _month <= 12 this._emitChange('month', this.month, valid) return valid }, isDayValid: function() { - var _day = parseInt(this.day) - var valid = _day >= 0 && _day <= this.daysMaxCalculation + let _day = parseInt(this.day) + let valid = _day >= 0 && _day <= this.daysMaxCalculation this._emitChange('day', this.day, valid) return valid }, isYearValid: function() { // Emit a change event - var valid - var minYear = this.mindate ? new Date(this.mindate).getFullYear() : null - var maxYear = this.maxdate ? new Date(this.maxdate).getFullYear() : null + let valid + let minYear = this.mindate ? new Date(this.mindate).getFullYear() : null + let maxYear = this.maxdate ? new Date(this.maxdate).getFullYear() : null if (minYear && maxYear) { valid = this.year >= minYear && this.year <= maxYear From a8635e8c8bc4f25a7ea1d1685c3627014598e549 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 26 Sep 2019 15:23:49 -0400 Subject: [PATCH 17/20] Add explanation about maxStartDate and minEndDate, Refactor calc max and min functions --- .../__tests__/pop_date_range.test.js | 6 +++ js/components/pop_date_range.js | 50 +++++++++++-------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/js/components/__tests__/pop_date_range.test.js b/js/components/__tests__/pop_date_range.test.js index ada35c15..17273bff 100644 --- a/js/components/__tests__/pop_date_range.test.js +++ b/js/components/__tests__/pop_date_range.test.js @@ -8,6 +8,12 @@ import { makeTestWrapper } from '../../test_utils/component_test_helpers' const PopDateRangeWrapper = makeTestWrapper({ components: { PopDateRange }, templatePath: 'pop_date_range.html', + data: function() { + return { + initialMinStartDate: '2019-09-14', + initialMaxEndDate: '2022-09-14', + } + }, }) describe('PopDateRange Test', () => { diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index 7abac268..0804066c 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -27,45 +27,51 @@ export default { }, data: function() { - var start = !!this.initialStartDate ? new Date(this.initialStartDate) : null - var end = !!this.initialEndDate ? new Date(this.initialEndDate) : null - var contractStart = new Date(this.initialMinStartDate) - var contractEnd = new Date(this.initialMaxEndDate) + let start = !!this.initialStartDate + ? new Date(this.initialStartDate) + : false + let contractStart = new Date(this.initialMinStartDate) + let minEndDate = start && start > contractStart ? start : contractStart + let end = !!this.initialEndDate ? new Date(this.initialEndDate) : false + let contractEnd = new Date(this.initialMaxEndDate) + let maxStartDate = end && end < contractEnd ? end : contractEnd + + // the maxStartDate and minEndDate change based on user input: + // the latest date the start can be is the PoP end date + // the earliest date the end can be is the PoP start date + // if the form is initialized with out a PoP, the maxStartDate and minEndDate + // default to the contract dates return { - maxStartDate: this.calcMaxStartDate(end, contractEnd), - minEndDate: this.calcMinEndDate(start, contractStart), + maxStartDate: maxStartDate, + minEndDate: minEndDate, } }, methods: { handleDateChange: function(event) { - if (event.name.includes(START_DATE)) { - if (event.valid != undefined && event.valid) { - var date = new Date(event.value) - this.minEndDate = this.calcMinEndDate(date) - } - } else if (event.name.includes(END_DATE)) { - if (event.valid != undefined && event.valid) { - var date = new Date(event.value) - this.maxStartDate = this.calcMaxStartDate(date) - } + if (event.name.includes(START_DATE) && event.valid) { + let date = new Date(event.value) + this.minEndDate = this.calcMinEndDate(date) + } else if (event.name.includes(END_DATE) && event.valid) { + let date = new Date(event.value) + this.maxStartDate = this.calcMaxStartDate(date) } }, - calcMaxStartDate: function(date, end = this.maxStartDate) { - if (!!date && date < end) { + calcMaxStartDate: function(date) { + if (!!date && date < this.maxStartDate) { return date } else { - return end + return this.maxStartDate } }, - calcMinEndDate: function(date, start = this.minEndDate) { - if (!!date && date > start) { + calcMinEndDate: function(date) { + if (!!date && date > this.minEndDate) { return date } else { - return start + return this.minEndDate } }, }, From 1912a9127fd6c134604779256d881eaeab79c2b7 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 26 Sep 2019 15:32:53 -0400 Subject: [PATCH 18/20] Add computed properties for Date object for dates used in functions --- js/components/date_selector.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index f6273231..e7372e75 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -102,8 +102,8 @@ export default { isYearValid: function() { // Emit a change event let valid - let minYear = this.mindate ? new Date(this.mindate).getFullYear() : null - let maxYear = this.maxdate ? new Date(this.maxdate).getFullYear() : null + let minYear = this.mindate ? this.minDateParsed.getFullYear() : null + let maxYear = this.maxdate ? this.maxDateParsed.getFullYear() : null if (minYear && maxYear) { valid = this.year >= minYear && this.year <= maxYear @@ -172,7 +172,7 @@ export default { minError: function() { if (this.isDateComplete) { - return new Date(this.mindate) > new Date(this.formattedDate) + return this.minDateParsed > this.dateParsed } return false @@ -180,11 +180,23 @@ export default { maxError: function() { if (this.isDateComplete) { - return new Date(this.maxdate) < new Date(this.formattedDate) + return this.maxDateParsed < this.dateParsed } return false }, + + maxDateParsed: function() { + return new Date(this.maxdate) + }, + + minDateParsed: function() { + return new Date(this.mindate) + }, + + dateParsed: function() { + return new Date(this.formattedDate) + }, }, methods: { From 2f3863b84d3b73ca47ef299cdd30139ec7de3acc Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 26 Sep 2019 15:37:38 -0400 Subject: [PATCH 19/20] Remove emitters for individual value changes --- js/components/date_selector.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index e7372e75..20aa6f7b 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -88,14 +88,12 @@ export default { isMonthValid: function() { let _month = parseInt(this.month) let valid = _month >= 0 && _month <= 12 - this._emitChange('month', this.month, valid) return valid }, isDayValid: function() { let _day = parseInt(this.day) let valid = _day >= 0 && _day <= this.daysMaxCalculation - this._emitChange('day', this.day, valid) return valid }, @@ -111,7 +109,6 @@ export default { valid = parseInt(this.year) >= 1 } - this._emitChange('year', this.year, valid) return valid }, @@ -214,10 +211,6 @@ export default { valid: this.isDateValid, }) }, - - _emitChange: function(name, value, valid) { - emitEvent('field-change', this, { value, name, valid }) - }, }, render: function(createElement) { From 0c54b61579337dade28177a332cf64f3995909c8 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 26 Sep 2019 16:19:30 -0400 Subject: [PATCH 20/20] Remove watch from date selector component --- js/components/date_selector.js | 5 ----- js/test_templates/clin_fields.html | 8 ++------ js/test_templates/pop_date_range.html | 6 ++---- js/test_templates/to_form.html | 6 +++--- templates/components/clin_fields.html | 4 ++-- templates/components/date_picker.html | 2 -- templates/components/pop_date_range.html | 4 +--- 7 files changed, 10 insertions(+), 25 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index 20aa6f7b..2717c033 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -20,10 +20,6 @@ export default { mindate: { type: String }, maxdate: { type: String }, nameTag: { type: String }, - watch: { - type: Boolean, - default: false, - }, optional: { type: Boolean, default: true, @@ -201,7 +197,6 @@ export default { emitEvent('field-change', this, { value: this.formattedDate, name: this.name, - watch: this.watch, valid: this.isDateValid, }) diff --git a/js/test_templates/clin_fields.html b/js/test_templates/clin_fields.html index 15d3027a..57fefe2c 100644 --- a/js/test_templates/clin_fields.html +++ b/js/test_templates/clin_fields.html @@ -311,8 +311,6 @@
- - @@ -401,8 +398,8 @@ maxlength="4" type="number" v-model="year" - max="" - min="" + max="2022" + min="2019" v-on:change="onInput" /> @@ -440,7 +437,6 @@ initialday="" initialyear="" - v-bind:watch='true' :optional='false' v-on:date-change='handleDateChange' inline-template> diff --git a/js/test_templates/pop_date_range.html b/js/test_templates/pop_date_range.html index 1c70e5e9..2d53ad9b 100644 --- a/js/test_templates/pop_date_range.html +++ b/js/test_templates/pop_date_range.html @@ -25,7 +25,6 @@ initialday="" initialyear="" - v-bind:watch='false' :optional='true' v-on:date-change='handleDateChange' inline-template> @@ -86,8 +85,8 @@ maxlength="4" type="number" v-model="year" - max="" - min="" + max="2022" + min="2019" v-on:change="onInput" /> @@ -125,7 +124,6 @@ initialday="" initialyear="" - v-bind:watch='false' :optional='true' v-on:date-change='handleDateChange' inline-template> diff --git a/js/test_templates/to_form.html b/js/test_templates/to_form.html index 6d091370..a22dc16f 100644 --- a/js/test_templates/to_form.html +++ b/js/test_templates/to_form.html @@ -203,7 +203,7 @@
- +
@@ -231,7 +231,7 @@
- +
@@ -251,7 +251,7 @@
- +
diff --git a/templates/components/clin_fields.html b/templates/components/clin_fields.html index 2baf6419..94ca2a5b 100644 --- a/templates/components/clin_fields.html +++ b/templates/components/clin_fields.html @@ -129,9 +129,9 @@
{% if fields %} - {{ PopDateRange(start_field=fields.start_date, end_field=fields.end_date, watch=True, optional=False, mindate=contract_start, maxdate=contract_end) }} + {{ PopDateRange(start_field=fields.start_date, end_field=fields.end_date, optional=False, mindate=contract_start, maxdate=contract_end) }} {% else %} - {{ PopDateRange(watch=True, optional=False, mindate=contract_start, maxdate=contract_end) }} + {{ PopDateRange(optional=False, mindate=contract_start, maxdate=contract_end) }} {% endif %}
diff --git a/templates/components/date_picker.html b/templates/components/date_picker.html index 165eee64..0a40f1bd 100644 --- a/templates/components/date_picker.html +++ b/templates/components/date_picker.html @@ -7,7 +7,6 @@ description=field.description, mindate=None, maxdate=None, - watch=False, optional=True) -%} diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index bde27736..676c7c69 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -1,7 +1,7 @@ {% from 'components/alert.html' import Alert %} {% from 'components/icon.html' import Icon %} -{% macro PopDateRange(start_field=None, end_field=None, mindate=mindate, maxdate=maxdate, watch=False, optional=True, index=None) %} +{% macro PopDateRange(start_field=None, end_field=None, mindate=mindate, maxdate=maxdate, optional=True, index=None) %} @@ -127,7 +126,6 @@ {% else %} :name-tag="'clins-' + clinIndex + '-end_date'" {% endif %} - v-bind:watch='{{ watch | string | lower }}' :optional='{{ optional | string | lower }}' v-on:date-change='handleDateChange' inline-template>