diff --git a/api/controller/expenditures.ts b/api/controller/expenditures.ts index abea3c2c6..2c3f5dc84 100644 --- a/api/controller/expenditures.ts +++ b/api/controller/expenditures.ts @@ -166,7 +166,6 @@ export async function getExpenditures(request: IRequest, response: Response, nex currentUserId: request.currentUser.id }); await checkDto(getExpendituresDto); - const expenditures = await getExpendituresAsync(getExpendituresDto); if (expenditures.csv) { response.type('text/csv'); diff --git a/api/models/entity/Contribution.ts b/api/models/entity/Contribution.ts index 63ee5a6c9..b1d41a5d1 100644 --- a/api/models/entity/Contribution.ts +++ b/api/models/entity/Contribution.ts @@ -661,9 +661,12 @@ export async function getContributionsByGovernmentIdAsync( } }; if (sort) { - if (!['date', 'status', 'campaignId', 'matchAmount', 'amount'].includes(sort.field)) { + if (!['date', 'status', 'campaignId', 'matchAmount', 'amount', 'oaeType', 'name'].includes(sort.field)) { throw new Error('Sort.field must be one of date, status, matchAmount, amount or campaignid'); } + if (sort.field === 'campaignId') { + sort.field = 'id'; + } if (!['ASC', 'DESC'].includes(sort.direction)) { throw new Error('Sort.direction must be one of ASC or DESC'); diff --git a/api/models/entity/Expenditure.ts b/api/models/entity/Expenditure.ts index 10e4bb6b1..325a562c8 100644 --- a/api/models/entity/Expenditure.ts +++ b/api/models/entity/Expenditure.ts @@ -389,7 +389,7 @@ export async function getExpendituresByGovernmentIdAsync( }; if (sort) { - if (!['date', 'status', 'campaignId'].includes(sort.field)) { + if (!['date', 'status', 'campaignId', 'amount'].includes(sort.field)) { throw new Error('Sort.field must be one of date, status or campaignId'); } diff --git a/api/services/contributionService.ts b/api/services/contributionService.ts index bb17b8062..0ffa4137a 100644 --- a/api/services/contributionService.ts +++ b/api/services/contributionService.ts @@ -169,7 +169,7 @@ export interface IGetContributionOptions { from?: string; to?: string; sort?: { - field: 'campaignId' | 'status' | 'date'; + field: 'campaignId' | 'status' | 'date' | 'id'; direction: 'ASC' | 'DESC'; }; format?: 'json' | 'csv' | 'geoJson' | 'xml'; @@ -580,18 +580,22 @@ export async function getMatchResultAsync(attrs: GetMatchResultAttrs): Promise { { field: 'name', title: 'Name', - sorting: false, render: rowData => { if ( rowData.contributorType === 'individual' || @@ -84,7 +83,6 @@ const columns = isGovAdmin => { { field: 'amount', title: 'Contribution Amount', - sorting: false, type: 'currency', }, { @@ -104,7 +102,6 @@ const columns = isGovAdmin => { cols.splice(1, 0, { field: 'campaignId', title: 'Campaign', - sorting: false, render: rowData => { return rowData && rowData.campaign ? rowData.campaign.name diff --git a/app/src/Pages/Portal/Expenses/ExpensesTable/ExpensesTable.js b/app/src/Pages/Portal/Expenses/ExpensesTable/ExpensesTable.js index 00fa757b6..09ad6e86b 100644 --- a/app/src/Pages/Portal/Expenses/ExpensesTable/ExpensesTable.js +++ b/app/src/Pages/Portal/Expenses/ExpensesTable/ExpensesTable.js @@ -79,13 +79,11 @@ const columns = isGovAdmin => [ { field: 'name', title: 'Name', - sorting: false, }, { field: 'amount', title: 'Amount', type: 'currency', - sorting: false, }, { field: 'paymentMethod', @@ -95,7 +93,6 @@ const columns = isGovAdmin => [ ? rowData.paymentMethod.replace(/_/g, ' ') : ''; }, - sorting: false, }, { field: 'status', diff --git a/app/src/components/ContributorMatchPicker/index.js b/app/src/components/ContributorMatchPicker/index.js index 993f715e0..e211ce891 100644 --- a/app/src/components/ContributorMatchPicker/index.js +++ b/app/src/components/ContributorMatchPicker/index.js @@ -67,11 +67,30 @@ const Header = props => { } // Switch color and symbol based on matchStrength const matchIcon = getMatchIcon(matchStrength, inPortland); + + if (!currentMatchId) { + return ( +

+ Contributor {matchIcon}{' '} + {currentMatchId && ( + + {matchSelectedText} + + )} +

+ ); + } return ( // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions

showModal({ component: 'MatchPickerForm', @@ -148,7 +167,10 @@ class contributorMatchPicker extends React.Component { } render() { - const inPortland = this.props.matchObj.inPortland; + if (!this.props.matchObj) { + return
; + } + const inPortland = (this.props.matchObj || {}).inPortland; const { totalPages, currentPage, pages } = this.state; const page = !isEmpty(pages) ? pages[currentPage] : [{}]; const { diff --git a/app/src/state/ducks/contributions.js b/app/src/state/ducks/contributions.js index 872bed9ba..437e4dd09 100644 --- a/app/src/state/ducks/contributions.js +++ b/app/src/state/ducks/contributions.js @@ -196,6 +196,17 @@ export function updateFilter(newFilterOptions) { (filterOptions.page * filterOptions.perPage) / newFilterOptions.perPage ); } + const existingSortField = filterOptions.sort; + const newSortField = newFilterOptions.sort; + if ( + existingSortField && + newSortField && + existingSortField.field === newSortField.field && + existingSortField.direction === newSortField.direction + ) { + const isAsc = existingSortField.direction === 'ASC'; + newFilterOptions.sort.direction = isAsc ? 'DESC' : 'ASC'; + } Object.entries(filterOptions).forEach(([key, value]) => { if (Object.prototype.hasOwnProperty.call(newFilterOptions, key)) filterOptions[key] = newFilterOptions[key]; diff --git a/app/src/state/ducks/expenditures.js b/app/src/state/ducks/expenditures.js index 4b0ad37db..eeccca3ee 100644 --- a/app/src/state/ducks/expenditures.js +++ b/app/src/state/ducks/expenditures.js @@ -164,6 +164,17 @@ export function updateFilter(newFilterOptions) { (filterOptions.page * filterOptions.perPage) / newFilterOptions.perPage ); } + const existingSortField = filterOptions.sort; + const newSortField = newFilterOptions.sort; + if ( + existingSortField && + newSortField && + existingSortField.field === newSortField.field && + existingSortField.direction === newSortField.direction + ) { + const isAsc = existingSortField.direction === 'ASC'; + newFilterOptions.sort.direction = isAsc ? 'DESC' : 'ASC'; + } Object.entries(filterOptions).forEach(([key, value]) => { if (Object.prototype.hasOwnProperty.call(newFilterOptions, key)) filterOptions[key] = newFilterOptions[key]; diff --git a/app/src/state/ducks/matches.js b/app/src/state/ducks/matches.js index 30a135e8d..43439954d 100644 --- a/app/src/state/ducks/matches.js +++ b/app/src/state/ducks/matches.js @@ -133,7 +133,7 @@ export const getCurrentContributionMatch = state => { export const getCurrentMatchResults = state => { const currentMatches = getCurrentContributionMatch(state); const matches = []; - const results = currentMatches.results; + const results = (currentMatches || {}).results; const currentContribution = getCurrentContribution(state); let match = {}; let selectedMatchId = ''; @@ -172,7 +172,7 @@ export const getCurrentMatchResults = state => { } } } - if (currentMatches.matchStrength !== 'exact') { + if (results && (currentMatches || {}).matchStrength !== 'exact') { if (currentContribution.matchStrength === 'none') { matches.unshift({ id: results.none, diff --git a/scripts/test.sh b/scripts/test.sh index 674a3beab..a8fb9f2ad 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -4,5 +4,7 @@ set -e export PATH=$PATH:$HOME/.local/bin +echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + sh scripts/api-test.sh sh scripts/app-test.sh