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

Add coverage dates using API for WCCF feature #3270

Merged
merged 3 commits into from
Oct 17, 2019
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 91 additions & 38 deletions fec/fec/static/js/widgets/contributions-by-state-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ function ContributionsByState() {
'history',
2020 // election year / cycle
];
// Where to find candidate's coverage dates
this.basePath_candidateCoverageDatesPath = [
'candidate',
'000', //candidate ID
'totals'
];
// Where to find the highest-earning candidates:
this.basePath_highestRaising = ['candidates', 'totals'];
// Where to find the list of states:
Expand Down Expand Up @@ -377,6 +383,87 @@ ContributionsByState.prototype.loadCandidateDetails = function(cand_id) {
.catch(function() {});
};

/**
* Format the dates into MM/DD/YYYY format.
* Pads single digits with leading 0.
*/
ContributionsByState.prototype.formatDate = function(date) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not really good or bad but since this is a pure function and we aren't referencing any particular ContributionsByState instance, we could define this as function formatDate(date) { rather than assign it to the class. But it works fine the way it is.

Copy link
Member Author

Choose a reason for hiding this comment

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

I decided to move the formatDate function to be locally scoped within the loadCandidateCoverageDates function for now since that's the only place it's used. If we need it later on, we can move it back out again.

// Adds one since js month uses zero based index
let month = date.getMonth() + 1;
if (month < 10) {
month = '0' + month;
}
let day = date.getDate();
if (day < 10) {
day = '0' + day;
}
return month + '/' + day + '/' + date.getFullYear();
};

/**
* Queries the API for the candidate's coverage dates for the currently-selected election
* Called by {@see displayUpdatedData_candidate() } and {@see displayUpdatedData_states() }
*/
ContributionsByState.prototype.loadCandidateCoverageDates = function() {
let instance = this;
this.basePath_candidateCoverageDatesPath[1] = this.candidateDetails.candidate_id;

let coverageDatesQuery = Object.assign(
{},
{
per_page: 100,
cycle: this.baseStatesQuery.cycle,
election_full: true
}
);

let theFetchUrl = buildUrl(
instance.basePath_candidateCoverageDatesPath,
coverageDatesQuery
);

window
.fetch(theFetchUrl, instance.fetchInitObj)
.then(function(response) {
if (response.status !== 200)
throw new Error('The network rejected the states request.');
Copy link
Contributor

Choose a reason for hiding this comment

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

I saw this the other day. I missed all of them. ...could you update the throw new Error messages so they're not all "...rejected the states request"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks @rfultz, I've updated the comments for this, can you take a look to see if it's more accurate now?

// else if (response.type == 'cors') throw new Error('CORS error');
response.json().then(data => {
if (data.results.length === 1) {
document
.querySelector('.states-table-timestamp')
.removeAttribute('style');
// Parse coverage date from API that is formatted like this: 2019-06-30T00:00:00+00:00
Copy link
Contributor

Choose a reason for hiding this comment

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

I love comments that explain what we get back from somewhere else

// into a string without timezone
let coverage_start_date = new Date(
data.results[0].coverage_start_date.substring(0, 19)
);
let coverage_end_date = new Date(
data.results[0].coverage_end_date.substring(0, 19)
);

// Remember the in-page elements
let theStartTimeElement = document.querySelector(
'.js-cycle-start-time'
);
let theEndTimeElement = document.querySelector('.js-cycle-end-time');
// Format the date and put it into the start time
theStartTimeElement.innerText = instance.formatDate(
coverage_start_date
);
// Format the date and put it into the end time
theEndTimeElement.innerText = instance.formatDate(coverage_end_date);
} else {
// Hide coverage dates display when there are zero results
document
.querySelector('.states-table-timestamp')
.setAttribute('style', 'opacity: 0;');
}
});
})
.catch(function() {});
};

/**
* Asks the API for the details of the candidate's committees for the currently-selected election
* Called by {@see displayUpdatedData_candidate() }
Expand Down Expand Up @@ -559,6 +646,8 @@ ContributionsByState.prototype.displayUpdatedData_candidate = function() {
this.baseStatesQuery.cycle
);

this.loadCandidateCoverageDates();

// Now that we have the candidate's personal details,
// we need to get the committee data
this.loadCandidateCommitteeDetails();
Expand Down Expand Up @@ -617,8 +706,8 @@ ContributionsByState.prototype.displayUpdatedData_states = function() {
theTableBody.innerHTML = theTbodyString;
}

// Update the time stamp above the states list
this.updateCycleTimeStamp();
// Update candidate's coverage dates above the states list
this.loadCandidateCoverageDates();

// Update the Individual Contributions button/link at the bottom
this.updateBrowseIndivContribsButton();
Expand Down Expand Up @@ -649,42 +738,6 @@ ContributionsByState.prototype.displayUpdatedData_total = function(data) {
else statesHolder.setAttribute('style', 'opacity: 0;');
};

/**
* Reads the date and office type and puts the correct date into the paqe, above the list of states
* Called from inside {@see displayUpdatedData_states() }
*/
ContributionsByState.prototype.updateCycleTimeStamp = function() {
let electionYear = this.baseStatesQuery.cycle;

// Remember the in-page elements
let theStartTimeElement = document.querySelector('.js-cycle-start-time');
let theEndTimeElement = document.querySelector('.js-cycle-end-time');

// If the election type is P, the start date is 1 January, three years previous
// Likewise, five years previous if S, or just one year previous for H
let theStartDate;
if (this.candidateDetails.office == 'P')
theStartDate = new Date(electionYear - 3, 1, 1);
else if (this.candidateDetails.office == 'S')
theStartDate = new Date(electionYear - 5, 1, 1);
else theStartDate = new Date(electionYear - 1, 1, 1);
theStartTimeElement.setAttribute(
'datetime',
theStartDate.getFullYear() + '-01-01'
);
// Put it into the start time
theStartTimeElement.innerText = `01/01/${theStartDate.getFullYear()}`;

// And the end date is just 31 December of the election_year
let theEndDate = new Date(electionYear, 1, 1);
theEndTimeElement.setAttribute(
'datetime',
theEndDate.getFullYear() + '-12-31'
);
// Finally put the ending year into the end time element
theEndTimeElement.innerText = `12/31/${theEndDate.getFullYear()}`;
};

/**
* Called when the typeahead element dispatches "typeahead:select"
* @param {jQuery.Event} e 'typeahead:select' event
Expand Down