Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace moment with date-fns in hca #12112

Closed
wants to merge 15 commits into from
Closed

Replace moment with date-fns in hca #12112

wants to merge 15 commits into from

Conversation

bkjohnson
Copy link
Contributor

@bkjohnson bkjohnson commented Apr 2, 2020

Description

This is part of department-of-veterans-affairs/va.gov-team#6763

This removes all explicit usage of moment from the hca app. The forms system still uses moment, so it will still get used implicitly in the app.

Testing done

Local unit testing

Screenshots

Acceptance criteria

  • [ ]

Definition of done

  • Events are logged appropriately
  • Documentation has been updated, if applicable
  • A link has been provided to the originating GitHub issue (or connected to it via ZenHub)
  • No sensitive information (i.e. PII/credentials/internal URLs/etc.) is captured in logging, hardcoded, or specs

It uses a helper that uses moment, and it isn't used anywhere else
Uses moment and it isn't used anywhere else
Note: the formatting is slightly different since date-fns doesn't append
a period to truncated month names like moment apparently does.
The lack of tests make me worry a bit - I may add some.
The dates are passed in as ISO date strings
This is a bit tricky - the function was using `_.get()` to try to access
a var that didn't exist, so the default formData object was always used
instead.  When moment() is called with any non-date object as its
parameter, it defaults to now.  So, essentially the `dob` variable was
always being assigned to the current datetime.
@va-bot va-bot temporarily deployed to vetsgov-pr-12112 April 2, 2020 23:24 Inactive
This undos some changes in the previous commit so that moment & lodash
are still used to calculate the dob const.  I may have missed something
in the refactor
@va-bot va-bot temporarily deployed to vetsgov-pr-12112 April 2, 2020 23:55 Inactive
@va-vfs-bot va-vfs-bot temporarily deployed to master/hca-moment April 3, 2020 00:13 Inactive
I misread the lodash function.  formData isn't the default, it is the
root object that the first argument (the string path) is applied to.

If _.get() returns undefined, moment() will parse it as the current
time.  The native JS Date.parse() will return NaN instead
@va-bot va-bot temporarily deployed to vetsgov-pr-12112 April 3, 2020 00:31 Inactive
@va-vfs-bot va-vfs-bot temporarily deployed to master/hca-moment April 3, 2020 00:52 Inactive
This isn't really necessary for the PR, but it is an improvement
@va-bot va-bot temporarily deployed to vetsgov-pr-12112 April 3, 2020 01:05 Inactive
@va-vfs-bot va-vfs-bot temporarily deployed to master/hca-moment April 3, 2020 01:25 Inactive
Copy link
Contributor Author

@bkjohnson bkjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some context.

@@ -65,7 +65,9 @@ export class ConfirmationPage extends React.Component {
<li>
<strong>{dateTitle}</strong>
<br />
<span>{moment(response.timestamp).format('MMM D, YYYY')}</span>
<span>
{format(parseISO(response.timestamp), 'MMM d, yyyy')}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

response.timestamp is expected to be an ISO-formatted date string.

@@ -89,7 +89,7 @@ export function getEnrollmentDetails(
blocks.push(
<>
<strong>You applied on: </strong>
{moment(applicationDate).format('MMMM D, YYYY')}
{format(Date.parse(applicationDate), 'MMMM d, yyyy')}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applicationDate is the first argument in getEnrollmentDetails. Even though there isn't a unit test specifically for this function, it is used in getWarningStatus(), and the second argument is passed directly through.

getWarningStatus(
HCA_ENROLLMENT_STATUSES.enrolled,
'2018-01-24T00:00:00.000-06:00',
'2018-01-24T00:00:00.000-06:00',
'FACILITY NAME',
),

@@ -98,7 +98,7 @@ export function getEnrollmentDetails(
blocks.push(
<>
<strong>We enrolled you on: </strong>
{moment(enrollmentDate).format('MMMM D, YYYY')}
{format(Date.parse(enrollmentDate), 'MMMM d, yyyy')}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enrollmentDate has the same story as applicationDate. It may be wise to add some unit tests for this function.

@@ -971,7 +971,7 @@ export function getAlertContent(
blocks.push(
<p key="you-applied-on">
<strong>You applied on:</strong>{' '}
{moment(applicationDate).format('MMMM D, YYYY')}
{format(Date.parse(applicationDate), 'MMMM d, yyyy')}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in an untested function. The only place it is used is in src/applications/personalization/dashboard/components/HCAStatusAlert.jsx

@@ -26,7 +26,7 @@ describe('hca <ConfirmationPage>', () => {
const tree = SkinDeep.shallowRender(<ConfirmationPage form={form} />);

expect(tree.subTree('.claim-list')).to.exist;
expect(tree.everySubTree('span')[2].text()).to.contain('Jan. 1, 2010');
expect(tree.everySubTree('span')[2].text()).to.contain('Jan 1, 2010');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting for abbreviated months in date-fns does not include a period for truncated months.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The content style guide indicates they have to have a period. I think we can use the escape character to add a period in the format string. Maybe

{format(parseISO(response.timestamp), "MMM'.' d, yyyy")}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll mess around with this - we may have some edge cases to account for with shorter months (i.e. March. 14, 2020), so I'll see how it handles those.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That true - we aren't supposed to abbreviate those.
external-content duckduckgo-9

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen some code that Eugene wrote to handle this exact thing for downtime notifications.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closing for now. The extra work to ensure that every format call meets the content guidelines isn't worth it in my opinion. I'd like for date-fns to provide a way of changing the default locale so we have an easier way of controlling things like this.

)} (${endDateInfo.description} from today)`,
);
}

if (veteranDateOfBirth) {
const dateOfBirth = moment(veteranDateOfBirth);
const dateOfBirth = Date.parse(veteranDateOfBirth);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

veteranDateOfBirth is also an ISO date string.


if (dateOfBirth.add(15, 'years').isAfter(moment(lastEntryDate))) {
if (isAfter(addYears(dateOfBirth, 15), Date.parse(lastEntryDate))) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lastEntryDate is also an ISO date string.

Comment on lines +57 to +59
const vetDOB = Date.parse(veteranDateOfBirth);
const spouseDOB = Date.parse(spouseDateOfBirth);
const marriage = Date.parse(marriageDate);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

marriageDate is the second argument in validateMarriageDate. All of these three arguments are ISO date strings.

validateMarriageDate(errors, '2010-01-01', {
spouseDateOfBirth: '2011-01-01',
veteranDateOfBirth: '1980-01-01',
discloseFinancialInformation: true,
});

src/applications/hca/validation.js Show resolved Hide resolved
const dob = moment(_.get(`dependents[${index}].dateOfBirth`, formData));
const dependent = Date.parse(dependentDate);
const dob =
Date.parse(formData?.dependents?.[index]?.dateOfBirth) || Date.now();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit confusing. The arguments in the previous _.get() call seem swapped - the object should be first and the path second.

However, the _.get() call was likely resulting in undefined each time, and moment(undefined) returns the current datetime:

Note: Function parameters default to undefined when not passed in. Moment treats moment(undefined) as moment().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the optional chaining returns undefined, Date.parse(undefined) will be NaN, so the || Date.now() should achieve the same thing that was previously happening.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arguments in the previous _.get() call seem swapped

It's lodash/fp.

if the optional chaining returns undefined, Date.parse(undefined) will be NaN, so the || Date.now() should achieve the same thing that was previously happening

This looks fine. maybe add a comment explaining that Date.parse returns NaN when applied to undefined.

@bkjohnson bkjohnson changed the title Hca moment Replace moment with date-fns in hca Apr 4, 2020
@bkjohnson bkjohnson marked this pull request as ready for review April 6, 2020 15:35
@bkjohnson bkjohnson requested a review from a team April 6, 2020 15:35
@@ -1,5 +1,5 @@
import React from 'react';
import moment from 'moment';
import { format } from 'date-fns';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love it when libraries use common terms for their functionality

@@ -26,7 +26,7 @@ describe('hca <ConfirmationPage>', () => {
const tree = SkinDeep.shallowRender(<ConfirmationPage form={form} />);

expect(tree.subTree('.claim-list')).to.exist;
expect(tree.everySubTree('span')[2].text()).to.contain('Jan. 1, 2010');
expect(tree.everySubTree('span')[2].text()).to.contain('Jan 1, 2010');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The content style guide indicates they have to have a period. I think we can use the escape character to add a period in the format string. Maybe

{format(parseISO(response.timestamp), "MMM'.' d, yyyy")}

@bkjohnson
Copy link
Contributor Author

Closing for now: #12112 (comment)

@bkjohnson bkjohnson closed this Apr 6, 2020
@timwright12 timwright12 deleted the hca-moment branch July 26, 2021 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants