-
Notifications
You must be signed in to change notification settings - Fork 0
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
[WIP] Full grants table #52
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
32b0c7a
quick styles for yearly sum bar charts
jessicamcinchak 036652a
keep grant descriptions to one line
jessicamcinchak 23ae546
first go at paginated requests, but offset is buggy
jessicamcinchak d567cdb
slightly closer attempt
jessicamcinchak 15aa7d9
fix merge conflict
jessicamcinchak 2a94b47
create GrantsTableWrapper for smaller paginated fetches
jessicamcinchak e3c89a3
add bool variables for fetchMore check
jessicamcinchak cef39ae
sort in separate step, more comments
jessicamcinchak File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
import React from 'react'; | ||
|
||
import { uniq, map, filter, findIndex, sortBy } from 'lodash'; | ||
|
||
import { useQuery, gql } from '@apollo/client'; | ||
|
||
import { stripHtml, extractYear } from '../utils'; | ||
|
||
import GrantTable from '../components/GrantTable'; | ||
|
||
const GET_ORGANIZATION_GRANTS = gql` | ||
query getOrg($organizationId: String!, $grantsFundedOffset: Int, $grantsReceivedOffset: Int, $limit: Int) { | ||
organization(uuid: $organizationId) { | ||
grantsFunded (offset: $grantsFundedOffset, limit: $limit, orderBy: uuid) { | ||
uuid | ||
dateFrom | ||
dateTo | ||
to { | ||
name | ||
uuid | ||
} | ||
amount | ||
description | ||
} | ||
grantsReceived (offset: $grantsReceivedOffset, limit: $limit, orderBy: uuid) { | ||
uuid | ||
dateFrom | ||
dateTo | ||
from { | ||
name | ||
uuid | ||
} | ||
amount | ||
description | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const GrantsTableWrapper = (props) => { | ||
const { loading, error, data, fetchMore } = useQuery(GET_ORGANIZATION_GRANTS, { | ||
variables: { | ||
organizationId: props.organizationId, | ||
grantsFundedOffset: 0, | ||
grantsReceivedOffset: 0, | ||
limit: 100 | ||
}, | ||
notifyOnNetworkStatusChange: true, // Update 'loading' prop after fetchMore | ||
}); | ||
|
||
if (loading) return 'Loading...'; | ||
if (error) return `Error! ${error}`; | ||
|
||
if (!data.organization) return `Failed to load org data!`; | ||
|
||
const loadMoreGrantsFunded = data.organization.grantsFunded.length < props.countGrantsFrom; | ||
const loadMoreGrantsReceived = data.organization.grantsReceived.length < props.countGrantsTo; | ||
|
||
// If our initial response is fewer records than the total grant count for either side, | ||
// fetchMore records and merge the arrays using apollo's offset-based pagination | ||
if (loadMoreGrantsFunded || loadMoreGrantsReceived) { | ||
fetchMore({ | ||
variables: { | ||
grantsFundedOffset: data.organization.grantsFunded.length, | ||
grantsReceivedOffset: data.organization.grantsReceived.length, | ||
}, | ||
}); | ||
} | ||
|
||
console.log( | ||
`Fetched ${data.organization.grantsFunded.length}/${props.countGrantsFrom} grants funded\ | ||
and ${data.organization.grantsReceived.length}/${props.countGrantsTo} grants received.` | ||
); | ||
|
||
// Do this after offset-basd fetching because arrays lengthen during cleansing | ||
const { | ||
grantsFunded, | ||
grantsReceived, | ||
fundedYearlySums, | ||
receivedYearlySums, | ||
} = cleanse(data.organization); | ||
|
||
return ( | ||
<GrantTable | ||
verb={props.showGrantSide} | ||
grants={props.showGrantSide === 'funded' ? grantsFunded : grantsReceived} | ||
sums={ | ||
props.showGrantSide === 'funded' ? fundedYearlySums : receivedYearlySums | ||
} | ||
/> | ||
); | ||
}; | ||
|
||
/** | ||
* Flatten, format, and sort our grant attributes | ||
* and calculate organization- and year-level totals | ||
*/ | ||
const cleanse = (organization) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this get a short comment about its role? |
||
// Flatten grantsReceived & grantsFunded nested objects | ||
const flattenedGrantsReceived = organization.grantsReceived.map((grant) => { | ||
const dateFrom = extractYear(grant.dateFrom); | ||
const dateTo = extractYear(grant.dateTo); | ||
const years = `${dateFrom} - ${dateTo}`; | ||
const desc = grant.description ? stripHtml(grant.description) : 'No description available'; | ||
|
||
return { | ||
org: grant.from.name, | ||
orgUuid: grant.from.uuid, | ||
description: desc, | ||
amount: grant.amount, | ||
uuid: grant.uuid, | ||
dateFrom, | ||
dateTo, | ||
years, | ||
summary: false, | ||
}; | ||
}); | ||
|
||
const flattenedGrantsFunded = organization.grantsFunded.map((grant) => { | ||
const dateFrom = extractYear(grant.dateFrom); | ||
const dateTo = extractYear(grant.dateTo); | ||
const years = `${dateFrom} - ${dateTo}`; | ||
const desc = grant.description ? stripHtml(grant.description) : 'No description available'; | ||
|
||
return { | ||
org: grant.to.name, | ||
orgUuid: grant.to.uuid, | ||
description: desc, | ||
amount: grant.amount, | ||
uuid: grant.uuid, | ||
dateFrom, | ||
dateTo, | ||
years, | ||
summary: false, | ||
}; | ||
}); | ||
|
||
// Sort flattened lists by org id (boring) and then the inverse of the start year. | ||
const sortedFlatGrantsReceived = sortBy( | ||
flattenedGrantsReceived, | ||
(grant) => grant.orgUuid + 1 / grant.dateFrom | ||
); | ||
|
||
const sortedFlatGrantsFunded = sortBy( | ||
flattenedGrantsFunded, | ||
(grant) => grant.orgUuid + 1 / grant.dateFrom | ||
); | ||
|
||
// Insert summary rows with org-level totals into the lists | ||
const { grants: grantsFunded, yearlySums: fundedYearlySums } = addSummaryRows( | ||
sortedFlatGrantsFunded | ||
); | ||
|
||
const { grants: grantsReceived, yearlySums: receivedYearlySums } = addSummaryRows( | ||
sortedFlatGrantsReceived | ||
); | ||
|
||
// Create a map containing a union of years in funded & received sums with zero values | ||
// This is used to ensure that the bar charts for funded/received have the same y axis categories | ||
const allYears = Object.keys({ | ||
...fundedYearlySums, | ||
...receivedYearlySums, | ||
}).reduce((acc, cur) => ({ ...acc, [cur]: 0 }), {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could this get longer variable names? |
||
|
||
return { | ||
grantsFunded, | ||
fundedYearlySums: { ...allYears, ...fundedYearlySums }, | ||
grantsReceived, | ||
receivedYearlySums: { ...allYears, ...receivedYearlySums }, | ||
}; | ||
}; | ||
|
||
/** | ||
* Add summary rows to table data, | ||
* and provide yearly totals. | ||
*/ | ||
function addSummaryRows(grantsOrig) { | ||
// Copy the provided array. | ||
const grants = grantsOrig; | ||
|
||
// Get orgs | ||
const uniqOrgs = uniq(map(grants, 'orgUuid')); | ||
|
||
// Get stats per org, and stick em right in the array of grants as summary rows! | ||
const yearlySums = {}; | ||
let insertAt = 0; | ||
|
||
uniqOrgs.forEach((orgUuid) => { | ||
let org = ''; | ||
|
||
const sum = filter(grants, { orgUuid }).reduce((memo, grant) => { | ||
// along the way, build our yearly sums! | ||
if (yearlySums[grant.dateFrom] > 0) { | ||
yearlySums[grant.dateFrom] += grant.amount; | ||
} else { | ||
yearlySums[grant.dateFrom] = grant.amount; | ||
} | ||
|
||
// This'll happen over and over but that is just fine. We just want the right name. | ||
org = grant.org; | ||
|
||
return memo + grant.amount; | ||
}, 0); | ||
|
||
// Find first row of this org's grant | ||
insertAt = findIndex(grants, { orgUuid }, insertAt); | ||
|
||
// Splice in their stats row there | ||
// Add 1 to search index since we inserted another row | ||
grants.splice(insertAt, 0, { | ||
org, | ||
description: `${org}:`, | ||
orgUuid, | ||
amount: sum, | ||
uuid: `summaryrow-${orgUuid}`, | ||
start: null, | ||
end: null, | ||
summary: true, | ||
}); | ||
}); | ||
|
||
return { grants, yearlySums }; | ||
}; | ||
|
||
export default GrantsTableWrapper; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving this block up around line 55 could shorten some of the code above, if I'm reading it correctly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah so this is a bit tricky -- we need the orginal length of the grantsFunded/grantsReceived response pre-cleanse in order to properly set offset. Because the cleanse will create and insert the "org header rows" directly into the array, we'd be trying to fetch something like 182/171 possible grants if this is defined upfront.
Maybe a phase 2 refactor though, would be nice to have shorter variable names here.