Skip to content

Commit

Permalink
Bug: CaseContact form date input (#5974)
Browse files Browse the repository at this point in the history
* use date_field input with max/min

* remove date conversion javascript

* CaseContact.occurred_at validation

* use constant for min date

* reformat validations to original style

* remove ranged date picker and related js

* Occurred at -> Date for error display
use min date constant & I18n in validation

* change default date to slashes
  • Loading branch information
thejonroberts authored Aug 14, 2024
1 parent 9105e43 commit 3f6c32c
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 367 deletions.
269 changes: 1 addition & 268 deletions app/javascript/__tests__/validated_form.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,274 +2,7 @@
require('jest')

const { Notifier } = require('../src/notifier.js')
const { NonDrivingContactMediumWarning, RangedDatePicker } = require('../src/validated_form.js')

const MILLISECONDS_IN_A_DAY = 86400000

describe('RangedDatePicker', () => {
let notifier

beforeEach(() => {
document.body.innerHTML =
`<form class="component-validated-form">
<input
data-date-format="yyyy/mm/dd"
data-provide="datepicker"
data-max-date="today"
class="component-date-picker-range"
component-name="occurred on"
type="text">
</form>
<div id="notifications">
<div class="messages">
</div>
<div id="async-waiting-indicator" style="display: none">
Saving <i class="load-spinner"></i>
</div>
<div id="async-success-indicator" class="success-notification" style="display: none">
Saved
</div>
<button id="toggle-minimize-notifications" style="display: none;">
<span>minimize notifications </span>
<span class="badge rounded-pill bg-success" style="display: none;"></span>
<span class="badge rounded-pill bg-warning" style="display: none;"></span>
<span class="badge rounded-pill bg-danger" style="display: none;"></span>
<i class="fa-solid fa-minus"></i>
</button>
</div>`
$(() => { // JQuery's callback for the DOM loading
notifier = new Notifier($('#notifications'))
})
})

describe('constructor', () => {
test('Throws appropriate errors when initialized with values other than a valid jQuery object', (done) => {
$(() => {
try {
expect(() => {
// eslint-disable-next-line no-new
new RangedDatePicker(3, notifier)
}).toThrow(TypeError)

expect(() => {
// eslint-disable-next-line no-new
new RangedDatePicker($('#non-existant'), notifier)
}).toThrow(ReferenceError)

done()
} catch (error) {
done(error)
}
})
})

test('throws a RangeError when min date is past max date', (done) => {
$(() => {
try {
const datePickerElement = $('input')
datePickerElement.attr('data-min-date', new Date(new Date().getTime() + MILLISECONDS_IN_A_DAY))

expect(() => {
// eslint-disable-next-line no-new
new RangedDatePicker(datePickerElement, notifier)
}).toThrow(RangeError)

done()
} catch (error) {
done(error)
}
})
})
})

describe('errorHighlightUI', () => {
let rangedDatePicker
let datePickerElement

beforeEach(() => {
$(() => {
datePickerElement = $('input')
rangedDatePicker = new RangedDatePicker($('input'), notifier)
})
})

test('draws a red border around the input if passed an error message', (done) => {
$(() => {
try {
expect(datePickerElement.css('border')).not.toMatch('2px solid red')
rangedDatePicker.errorHighlightUI('An error')

expect(datePickerElement.css('border')).toBe('2px solid red')
done()
} catch (error) {
done(error)
}
})
})

test('removes the red border around the input when passed a falsy value if it was previously highlighted to indicate an error', (done) => {
$(() => {
try {
expect(datePickerElement.css('border')).not.toMatch('solid red')
rangedDatePicker.errorHighlightUI('An error')

expect(datePickerElement.css('border')).toBe('2px solid red')

rangedDatePicker.errorHighlightUI()

expect(datePickerElement.css('border')).not.toMatch('solid red')
done()
} catch (error) {
done(error)
}
})
})
})

describe('getErrorState', () => {
let rangedDatePicker
let datePickerElement

beforeEach(() => {
$(() => {
datePickerElement = $('input')
datePickerElement.attr('data-min-date', new Date(new Date().getTime() - (2 * MILLISECONDS_IN_A_DAY)))
rangedDatePicker = new RangedDatePicker($('input'), notifier)
})
})

test('returns an error message if the user input date is past max', (done) => {
$(() => {
try {
datePickerElement.val(new Date(new Date().getTime() + MILLISECONDS_IN_A_DAY))

const errorState = rangedDatePicker.getErrorState()

expect(typeof errorState).toBe('string')
expect(errorState.length).toBeGreaterThan(0)
done()
} catch (error) {
done(error)
}
})
})

test('returns an error message if the user input date is before min', (done) => {
$(() => {
try {
datePickerElement.val(new Date(new Date().getTime() - (3 * MILLISECONDS_IN_A_DAY)))

const errorState = rangedDatePicker.getErrorState()

expect(typeof errorState).toBe('string')
expect(errorState.length).toBeGreaterThan(0)
done()
} catch (error) {
done(error)
}
})
})

test('returns a falsy value if the user input string is between min and max', (done) => {
$(() => {
try {
datePickerElement.val(new Date(new Date().getTime() - MILLISECONDS_IN_A_DAY))

const errorState = rangedDatePicker.getErrorState()

expect(errorState).toBeFalsy()
done()
} catch (error) {
done(error)
}
})
})
})

describe('showUserError', () => {
let rangedDatePicker
let notifierElement

beforeEach(() => {
$(() => {
notifierElement = $('#notifications')
rangedDatePicker = new RangedDatePicker($('input'), notifier)
})
})

test('shows an error notification to the user', (done) => {
$(() => {
try {
const errorText = 'Q~Au\\`FMET"["8.JKB_M'

rangedDatePicker.showUserError(errorText)

const notifications = notifierElement.find('.danger-notification')
expect(notifications[0].innerHTML).toContain(errorText)
done()
} catch (error) {
done(error)
}
})
})

test('changes the text of the error notification if it already exists', (done) => {
$(() => {
try {
const errorText = 'Q~Au\\`FMET"["8.JKB_M'
const errorText2 = 'l6o4H/z*KnA:/AFg.-.G'

rangedDatePicker.showUserError(errorText)

const notifications = notifierElement.find('.danger-notification')
expect(notifications[0].innerHTML).toContain(errorText)

rangedDatePicker.showUserError(errorText2)

expect(notifierElement[0].innerHTML).not.toContain(errorText)
expect(notifications[0].innerHTML).toContain(errorText2)
done()
} catch (error) {
done(error)
}
})
})
})

describe('removeUserError', () => {
let rangedDatePicker
let notifierElement

beforeEach(() => {
$(() => {
notifierElement = $('#notifications')
rangedDatePicker = new RangedDatePicker($('input'), notifier)
})
})

test('removes the error notification shown to the user', (done) => {
$(() => {
try {
const errorText = 'Q~Au\\`FMET"["8.JKB_M'

rangedDatePicker.showUserError(errorText)

const notifications = notifierElement.find('.danger-notification')
expect(notifications[0].innerHTML).toContain(errorText)

rangedDatePicker.removeUserError()

expect(notifierElement.find('.danger-notification').length).toBe(0)
expect(notifierElement[0].innerHTML).not.toContain(errorText)
done()
} catch (error) {
done(error)
}
})
})
})
})
const { NonDrivingContactMediumWarning } = require('../src/validated_form.js')

describe('NonDrivingContactMediumWarning', () => {
let checkboxes
Expand Down
12 changes: 0 additions & 12 deletions app/javascript/src/case_contact.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
/* global $ */

import Swal from 'sweetalert2'

function enGBDateString (date) {
return date.toLocaleDateString('en-GB').split('/').reverse().join('-')
}

function convertDateToSystemTimeZone (date) {
return new Date((typeof date === 'string' ? new Date(date) : date))
}
Expand Down Expand Up @@ -48,13 +43,6 @@ async function fireSwalFollowupAlert () {
}

$(() => { // JQuery's callback for the DOM loading
const caseOccurredAt = $('#case_contact_occurred_at')
const timeZoneConvertedDate = enGBDateString(new Date())

if (enGBDateString(convertDateToSystemTimeZone(caseOccurredAt.val())) === timeZoneConvertedDate) {
caseOccurredAt.val(timeZoneConvertedDate)
}

$('[data-toggle="tooltip"]').tooltip()
$('.followup-button').on('click', displayFollowupAlert)
})
Expand Down
64 changes: 1 addition & 63 deletions app/javascript/src/validated_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,62 +150,6 @@ class ValidatableFormSectionComponent {
}
}

class RangedDatePicker extends ValidatableFormSectionComponent {
constructor (componentElementsAsJQuery, notifier) {
super(componentElementsAsJQuery, notifier)

const maxDateValue = this.componentElementsAsJQuery.attr('data-max-date')
const minDateValue = this.componentElementsAsJQuery.attr('data-min-date')
this.name = this.componentElementsAsJQuery.attr('component-name')

const max = maxDateValue === 'today' ? new Date() : new Date(maxDateValue)
const min = minDateValue === 'today' ? new Date() : new Date(minDateValue)

this.max = max
this.min = min

if (min instanceof Date && max instanceof Date && max < min) {
throw new RangeError('The minimum date for the component was set to be later than the maximum date')
}
}

errorHighlightUI (errorState) {
if (errorState) {
this.componentElementsAsJQuery.css('border', '2px solid red')
} else {
this.componentElementsAsJQuery.css('border', '')
}
}

getErrorState () {
const setDate = new Date(this.componentElementsAsJQuery.val())
const { max, min } = this

if (setDate > max && !isNaN(max)) {
return `Date for ${this.name} is past maximum allowed date of ${max.toDateString()}`
} else if (setDate < min && !isNaN(min)) {
return `Date for ${this.name} is before minimum allowed date of ${min.toDateString()}`
}
}

showUserError (errorMsg) {
TypeChecker.checkNonEmptyString(errorMsg, 'errorMsg')

if (this.errorNotification) {
this.errorNotification.setText(errorMsg)
} else if (this.notifier) {
this.errorNotification = this.notifier.notify(errorMsg, 'error', false)
}
}

removeUserError () {
if (this.errorNotification) {
this.errorNotification.dismiss()
delete this.errorNotification
}
}
}

class NonDrivingContactMediumWarning extends ValidatableFormSectionComponent {
constructor (allInputs, notifier) {
super(allInputs, notifier)
Expand Down Expand Up @@ -306,12 +250,6 @@ $(() => { // JQuery's callback for the DOM loading
const notificationsElement = $('#notifications')
const pageNotifier = notificationsElement.length ? new Notifier(notificationsElement) : null

validatedFormCollection.find('.component-date-picker-range').each(function () {
safeInstantiateComponent('ranged date picker', () => {
validatableFormSectionComponents.push(new RangedDatePicker($(this), pageNotifier))
})
})

if ($('#case_contact_miles_driven').length) {
safeInstantiateComponent('non driving contact medium warning', () => {
const contactMediumWithMilesDrivenWarning = new NonDrivingContactMediumWarning(validatedFormCollection.find('.contact-medium.form-group input:not([type=hidden]), #case_contact_miles_driven'), pageNotifier)
Expand Down Expand Up @@ -353,4 +291,4 @@ $(() => { // JQuery's callback for the DOM loading
})
})

module.exports = { NonDrivingContactMediumWarning, RangedDatePicker }
module.exports = { NonDrivingContactMediumWarning }
Loading

0 comments on commit 3f6c32c

Please sign in to comment.