|

   Veteran Tools Platform - Developer Documentation

There are no notes for this item.

PropRequired?TypeDefaultDescription
required No bool
validation No {
  valid: bool,
  message: string }
label No string
name Yes string
date Yes {
  day: {
  value: string,
  dirty: bool },
  month: {
  value: string,
  dirty: bool },
  year: {
  value: string,
  dirty: bool } }
onValueChange Yes func
toolTipText No string
requiredMessage No string 'Please provide a response'
invalidMessage No string 'Please provide a valid date'
<div id="reactMount" data-tpl="errorabledate">
    <div class="false"><label>Please tell us a date<span class="form-required-span">*</span></label>
        <div>
            <div class="usa-date-of-birth row">
                <div class="form-datefield-month">
                    <div><label for="errorable-select-31">Month</label><select id="errorable-select-31" name="Errorable DateMonth" autocomplete="false"><option value=""></option><option value="1">Jan</option><option value="2">Feb</option><option value="3">Mar</option><option selected="" value="4">Apr</option><option value="5">May</option><option value="6">Jun</option><option value="7">Jul</option><option value="8">Aug</option><option value="9">Sep</option><option value="10">Oct</option><option value="11">Nov</option><option value="12">Dec</option></select></div>
                </div>
                <div class="form-datefield-day">
                    <div><label for="errorable-select-32">Day</label><select id="errorable-select-32" name="Errorable DateDay" autocomplete="false"><option value=""></option><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option selected="" value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option><option value="21">21</option><option value="22">22</option><option value="23">23</option><option value="24">24</option><option value="25">25</option><option value="26">26</option><option value="27">27</option><option value="28">28</option><option value="29">29</option><option value="30">30</option></select></div>
                </div>
                <div class="usa-datefield usa-form-group usa-form-group-year">
                    <div><label for="errorable-number-input-33">Year</label><input type="number" min="1900" max="2119" autocomplete="false" id="errorable-number-input-33" name="Errorable DateYear" pattern="[0-9]{4}" value="1983" /></div>
                </div>
            </div>
            <div><button>More Info</button>
                <div aria-hidden="true">This is a tool tip<br/><button>Close</button></div>
            </div>
        </div>
    </div>
</div>
<script>
    window.currentProps = {
        "package": {
            "name": "department-of-veteran-affairs/jean-pants",
            "version": "0.1.0"
        },
        "assetPath": "/design-system/",
        "isProduction": true,
        "componentSourcePath": "./ErrorableDate.jsx",
        "required": true,
        "label": "Please tell us a date",
        "name": "Errorable Date",
        "date": {
            "day": {
                "value": "14",
                "dirty": null
            },
            "month": {
                "value": "4",
                "dirty": null
            },
            "year": {
                "value": "1983",
                "dirty": null
            }
        },
        "toolTipText": "This is a tool tip",
        "requiredMessage": "Please provide a response",
        "invalidMessage": "Please provide a valid date"
    }
</script>
import React from 'react';
import ErrorableDate from './ErrorableDate';

export default function ErrorableDateExample(props) {
  return (
    <ErrorableDate
      label={props.label}
      onValueChange={(e) => {e.target.checked}}
      {...props}
    />);
}
package:
  name: department-of-veteran-affairs/jean-pants
  version: 0.1.0
assetPath: /design-system/
isProduction: true
componentSourcePath: ./ErrorableDate.jsx
required: true
label: Please tell us a date
name: Errorable Date
date:
  day:
    value: '14'
    dirty: null
  month:
    value: '4'
    dirty: null
  year:
    value: '1983'
    dirty: null
toolTipText: This is a tool tip
requiredMessage: Please provide a response
invalidMessage: Please provide a valid date
  • Content:
    /* eslint-disable jsx-a11y/label-has-for */
    import PropTypes from 'prop-types';
    import React from 'react';
    import _ from 'lodash';
    import { set } from 'lodash/fp';
    import moment from 'moment';
    
    import ErrorableSelect from '../ErrorableSelect/ErrorableSelect';
    import ErrorableNumberInput from '../ErrorableNumberInput/ErrorableNumberInput';
    
    import ToolTip from '../../../Tooltip/Tooltip';
    
    import {
      isDirtyDate,
      isValidPartialDate,
      isNotBlankDateField,
      validateCustomFormComponent
    } from '../../../../utils/validations';
    import { months, days } from '../../../../utils/options-for-select.js';
    
    /**
     * A date input field that accepts values for month and year
     */
    
    class ErrorableDate extends React.Component {
      constructor() {
        super();
        this.handleChange = this.handleChange.bind(this);
      }
    
      componentWillMount() {
        this.id = _.uniqueId('date-input-');
      }
    
      handleChange(path, update) {
        let date = set(path, update, this.props.date);
        if (!date.month.value) {
          date = set('day.value', '', date);
        }
    
        this.props.onValueChange(date);
      }
    
      render() {
        const { day, month, year } = this.props.date;
    
        let daysForSelectedMonth = [];
        if (month.value) {
          daysForSelectedMonth = days[month.value];
        }
    
        // we want to do validations in a specific order, so we show the message
        // that makes the most sense to the user
        let isValid = true;
        let errorMessage;
        if (isDirtyDate(this.props.date)) {
          // make sure the user enters a full date first, if required
          if (this.props.required && !isNotBlankDateField(this.props.date)) {
            isValid = false;
            errorMessage = this.props.requiredMessage;
            // make sure the user has entered a minimally valid date
          } else if (!isValidPartialDate(day.value, month.value, year.value)) {
            isValid = false;
            errorMessage = this.props.invalidMessage;
          } else {
            const validationResult = validateCustomFormComponent(
              this.props.validation
            );
            isValid = validationResult.valid;
            errorMessage = validationResult.message;
          }
        }
    
        let errorSpanId;
        let errorSpan = '';
        if (!isValid) {
          errorSpanId = `${this.inputId}-error-message`;
          errorSpan = (
            <span className="usa-input-error-message" role="alert" id={errorSpanId}>
              <span className="sr-only">Error</span> {errorMessage}
            </span>
          );
        }
    
        // Adds ToolTip if text is provided.
        let toolTip;
        if (this.props.toolTipText) {
          toolTip = (
            <ToolTip
              tabIndex={this.props.tabIndex}
              toolTipText={this.props.toolTipText}/>
          );
        }
    
        return (
          <div className={!isValid && 'input-error-date'}>
            <label>
              {this.props.label ? this.props.label : 'Date of birth'}
              {this.props.required && <span className="form-required-span">*</span>}
            </label>
            {errorSpan}
            <div
              className={isValid ? undefined : 'usa-input-error form-error-date'}>
              <div className="usa-date-of-birth row">
                <div className="form-datefield-month">
                  <ErrorableSelect
                    errorMessage={isValid ? undefined : ''}
                    autocomplete="false"
                    label="Month"
                    name={`${this.props.name}Month`}
                    options={months}
                    value={month}
                    onValueChange={update => {
                      this.handleChange('month', update);
                    }}/>
                </div>
                <div className="form-datefield-day">
                  <ErrorableSelect
                    errorMessage={isValid ? undefined : ''}
                    autocomplete="false"
                    label="Day"
                    name={`${this.props.name}Day`}
                    options={daysForSelectedMonth}
                    value={day}
                    onValueChange={update => {
                      this.handleChange('day', update);
                    }}/>
                </div>
                <div className="usa-datefield usa-form-group usa-form-group-year">
                  <ErrorableNumberInput
                    errorMessage={isValid ? undefined : ''}
                    autocomplete="false"
                    label="Year"
                    name={`${this.props.name}Year`}
                    max={moment()
                      .add(100, 'year')
                      .year()}
                    min="1900"
                    pattern="[0-9]{4}"
                    field={year}
                    onValueChange={update => {
                      this.handleChange('year', update);
                    }}/>
                </div>
              </div>
              {toolTip}
            </div>
          </div>
        );
      }
    }
    
    ErrorableDate.propTypes = {
      /* Render marker indicating field is required. */
      required: PropTypes.bool,
      /* object or array. Result of custom validation. Should include a valid prop and a message prop */
      validation: PropTypes.shape({
        valid: PropTypes.bool,
        message: PropTypes.string
      }),
      /* Label for entire question. */
      label: PropTypes.string,
      /* Used to create unique name attributes for each input. */
      name: PropTypes.string.isRequired,
      /* Date value. Should have month, day, and year props */
      date: PropTypes.shape({
        day: PropTypes.shape({
          value: PropTypes.string,
          dirty: PropTypes.bool
        }),
        month: PropTypes.shape({
          value: PropTypes.string,
          dirty: PropTypes.bool
        }),
        year: PropTypes.shape({
          value: PropTypes.string,
          dirty: PropTypes.bool
        })
      }).isRequired,
      /* a function with this prototype: (newValue) */
      onValueChange: PropTypes.func.isRequired,
      /* String with help text for user. */
      toolTipText: PropTypes.string,
      requiredMessage: PropTypes.string,
      invalidMessage: PropTypes.string
    };
    
    ErrorableDate.defaultProps = {
      requiredMessage: 'Please provide a response',
      invalidMessage: 'Please provide a valid date'
    };
    
    export default ErrorableDate;
    
  • URL: /components/raw/errorabledate/ErrorableDate.jsx
  • Filesystem Path: src/components/form/controls/ErrorableDate/ErrorableDate.jsx
  • Size: 5.9 KB
  • Content:
    import React from 'react';
    // import SkinDeep from 'skin-deep';
    import { expect } from 'chai';
    import { shallow } from 'enzyme';
    import { axeCheck } from '../../../../../lib/testing/helpers';
    import ErrorableDate from './ErrorableDate';
    import { makeField } from '../../../../helpers/fields.js';
    
    describe('<ErrorableDate>', () => {
      it('renders input elements', () => {
        const date = {
          day: makeField(1),
          month: makeField(12),
          year: makeField(2010)
        };
        const tree = shallow(
          <ErrorableDate date={date} onValueChange={(_update) => {}}/>);
        expect(tree.find('ErrorableNumberInput')).to.have.lengthOf(1);
        expect(tree.find('ErrorableSelect')).to.have.lengthOf(2);
      });
      it('displays required message', () => {
        const date = {
          day: makeField(''),
          month: makeField(''),
          year: makeField('')
        };
        date.year.dirty = true;
        date.month.dirty = true;
        date.day.dirty = true;
    
        const tree = shallow(
          <ErrorableDate required date={date} onValueChange={(_update) => {}}/>);
    
        expect(tree.find('.usa-input-error')).not.to.be.empty;
        expect(tree.find('.usa-input-error-message').text()).to.equal('Error Please provide a response');
      });
      it('displays invalid message', () => {
        const date = {
          day: makeField(''),
          month: makeField(''),
          year: makeField('1890')
        };
        date.year.dirty = true;
        date.month.dirty = true;
        date.day.dirty = true;
    
        const tree = shallow(
          <ErrorableDate date={date} onValueChange={(_update) => {}}/>);
    
        expect(tree.find('.usa-input-error')).not.to.be.empty;
        expect(tree.find('.usa-input-error-message').text()).to.equal('Error Please provide a valid date');
      });
    
      it('does not show invalid message for month year date', () => {
        const date = {
          day: makeField(''),
          month: makeField('12'),
          year: makeField('2003')
        };
        date.year.dirty = true;
        date.month.dirty = true;
        date.day.dirty = true;
    
        const tree = shallow(
          <ErrorableDate date={date} onValueChange={(_update) => {}}/>);
        expect(tree.find('.usa-input-error')).to.have.length(0);
      });
    
      it('displays custom message', () => {
        const date = {
          day: makeField('3'),
          month: makeField(''),
          year: makeField('2010')
        };
        date.year.dirty = true;
        date.month.dirty = true;
        date.day.dirty = true;
    
        const tree = shallow(
          <ErrorableDate date={date} validation={{ valid: false, message: 'Test' }} onValueChange={(_update) => {}}/>);
    
        expect(tree.find('.usa-input-error')).not.to.be.empty;
        expect(tree.find('.usa-input-error-message').text()).to.equal('Error Test');
      });
      it('displays custom message from array', () => {
        const date = {
          day: makeField('3'),
          month: makeField(''),
          year: makeField('2010')
        };
        date.year.dirty = true;
        date.month.dirty = true;
        date.day.dirty = true;
    
        const tree = shallow(
          <ErrorableDate
            date={date}
            validation={[
              { valid: true, message: 'NotShownMessage' },
              { valid: false, message: 'Test' }
            ]}
            onValueChange={(_update) => {}}/>
        );
    
        expect(tree.find('.usa-input-error')).not.to.be.empty;
        expect(tree.find('.usa-input-error-message').text()).to.equal('Error Test');
      });
    
      it('should pass aXe check', () => {
        const date = {
          day: makeField(''),
          month: makeField(''),
          year: makeField('1890')
        };
    
        return axeCheck(<ErrorableDate date={date} onValueChange={(_update) => {}}/>);
      });
    
      it('should pass aXe check when errorMessage is set', () => {
        const date = {
          day: makeField(''),
          month: makeField(''),
          year: makeField('1890')
        };
        date.year.dirty = true;
        date.month.dirty = true;
        date.day.dirty = true;
    
        return axeCheck(<ErrorableDate date={date} onValueChange={(_update) => {}}/>);
      });
    });
    
  • URL: /components/raw/errorabledate/ErrorableDate.unit.spec.jsx
  • Filesystem Path: src/components/form/controls/ErrorableDate/ErrorableDate.unit.spec.jsx
  • Size: 3.9 KB
  • Handle: @errorabledate
  • Preview:
  • Filesystem Path: src/components/form/controls/ErrorableDate/ErrorableDate.njk