From c59f64a658482e93b437134c0d5cc0351909290e Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Thu, 6 Jul 2017 15:26:35 -0400 Subject: [PATCH 01/97] Update to React 15.6.1 / Redux 3.7.1 / React-Redux 5.0.5. Added `prop-types` package. Replaced React.PropTypes with PropTypes from `prop-types` package. --- criticalVersions.json | 4 +- package.json | 13 +++--- src/js/components/about/NextStepsBox.jsx | 17 ++++---- src/js/components/account/Account.jsx | 3 +- src/js/components/account/AccountHeader.jsx | 3 +- src/js/components/account/AccountOverview.jsx | 3 +- src/js/components/account/InvalidAccount.jsx | 3 +- src/js/components/account/LoadingAccount.jsx | 3 +- .../account/awards/AccountAwardsSection.jsx | 11 ++--- .../filters/objectClass/ObjectClassFilter.jsx | 5 ++- .../programActivity/ProgramActivityFilter.jsx | 11 ++--- .../filterGroups/ObjectClassFilterGroup.jsx | 5 ++- .../ProgramActivityFilterGroup.jsx | 5 ++- .../filterGroups/TimePeriodDRFilterGroup.jsx | 5 ++- .../filterGroups/TimePeriodFYFilterGroup.jsx | 5 ++- .../rank/AccountRankVisualizationSection.jsx | 17 ++++---- .../sankey/SankeyVisualization.jsx | 5 ++- .../sankey/SankeyVisualizationHorizontal.jsx | 7 +-- .../sankey/SankeyVisualizationVertical.jsx | 5 ++- .../sankey/components/DirectionLabel.jsx | 11 ++--- .../sankey/components/ItemLabel.jsx | 11 ++--- .../sankey/components/ItemLegend.jsx | 13 +++--- .../sankey/components/SankeyBar.jsx | 13 +++--- .../sankey/components/SankeyDisclosures.jsx | 3 +- .../sankey/components/SankeyFlow.jsx | 7 +-- .../sankey/components/SankeyFlowVertical.jsx | 7 +-- .../sankey/components/SankeyMessage.jsx | 3 +- .../AccountTimeVisualizationPeriodButton.jsx | 9 ++-- .../time/AccountTimeVisualizationSection.jsx | 9 ++-- .../visualizations/time/TimeVisualization.jsx | 15 ++++--- .../time/chart/BarChartStacked.jsx | 23 +++++----- .../visualizations/time/chart/OutlayItem.jsx | 9 ++-- .../time/chart/StackedBarItem.jsx | 23 +++++----- src/js/components/agency/AgencyContent.jsx | 3 +- src/js/components/agency/AgencyPage.jsx | 9 ++-- .../components/agency/footer/AgencyFooter.jsx | 3 +- .../components/agency/header/AgencyHeader.jsx | 3 +- .../agency/overview/AgencyOverview.jsx | 3 +- .../agency/sidebar/AgencySidebar.jsx | 7 +-- .../components/agency/sidebar/SidebarLink.jsx | 9 ++-- .../objectClass/MajorObjectClasses.jsx | 9 ++-- .../objectClass/MinorObjectClasses.jsx | 9 ++-- .../objectClass/ObjectClassCell.jsx | 43 ++++++++++--------- .../objectClass/ObjectClassTooltip.jsx | 23 +++++----- .../objectClass/ObjectClassTreeMap.jsx | 11 ++--- .../obligated/HorizontalBarItem.jsx | 11 ++--- .../obligated/ObligatedGraph.jsx | 16 +++---- .../obligated/ObligatedVisualization.jsx | 11 ++--- .../recipient/RecipientChart.jsx | 19 ++++---- .../recipient/RecipientTooltip.jsx | 9 ++-- .../recipient/RecipientVisualization.jsx | 23 +++++----- .../visualizations/recipient/ScopeList.jsx | 5 ++- src/js/components/article/Breadcrumb.jsx | 3 +- src/js/components/award/AgencyInfo.jsx | 5 ++- src/js/components/award/Award.jsx | 7 +-- src/js/components/award/AwardAmounts.jsx | 7 +-- src/js/components/award/AwardInfo.jsx | 3 +- src/js/components/award/AwardInfoBar.jsx | 3 +- src/js/components/award/DetailRow.jsx | 9 ++-- src/js/components/award/InfoSnippet.jsx | 5 ++- src/js/components/award/LoanAmounts.jsx | 5 ++- src/js/components/award/RecipientAddress.jsx | 5 ++- src/js/components/award/RecipientInfo.jsx | 3 +- src/js/components/award/SummaryBar.jsx | 3 +- .../award/contract/AwardContract.jsx | 5 ++- .../award/contract/ContractDetails.jsx | 7 +-- .../award/details/DetailsSection.jsx | 7 +-- .../award/details/DetailsTabBar.jsx | 7 +-- .../award/details/DetailsTabItem.jsx | 11 ++--- .../details/additional/AdditionalGroup.jsx | 7 +-- .../details/additional/AdditionalRow.jsx | 5 ++- .../AssistanceAdditionalDetails.jsx | 3 +- .../additional/ContractAdditionalDetails.jsx | 3 +- .../AwardFinancialAssistance.jsx | 5 ++- .../FinancialAssistanceDetails.jsx | 5 ++- .../award/subawards/SubawardsTable.jsx | 13 +++--- .../subawards/cells/SubawardsHeaderCell.jsx | 13 +++--- .../table/AssistanceTransactionsTable.jsx | 9 ++-- .../award/table/ContractTransactionsTable.jsx | 9 ++-- .../award/table/FinancialSystemTable.jsx | 9 ++-- .../award/table/LoanTransactionsTable.jsx | 9 ++-- .../award/table/SummaryPageTableMessage.jsx | 3 +- .../AssistanceTransactionGenericCell.jsx | 9 ++-- .../cells/AssistanceTransactionHeaderCell.jsx | 13 +++--- .../award/table/cells/FinSysGenericCell.jsx | 9 ++-- .../award/table/cells/FinSysHeaderCell.jsx | 13 +++--- .../table/cells/LoanTransactionHeaderCell.jsx | 13 +++--- .../cells/TransactionTableGenericCell.jsx | 9 ++-- .../cells/TransactionTableHeaderCell.jsx | 13 +++--- .../award/visualizations/AmountsChart.jsx | 13 +++--- .../award/visualizations/AwardLabels.jsx | 27 ++++++------ .../award/visualizations/AwardLabelsLine.jsx | 4 +- .../award/visualizations/AwardLabelsPoly.jsx | 13 +++--- .../award/visualizations/CurrentAwardBar.jsx | 11 ++--- .../award/visualizations/IndividualBar.jsx | 7 +-- .../visualizations/PotentialAwardBar.jsx | 11 ++--- .../award/visualizations/SubAwardBar.jsx | 11 ++--- .../glossary/AnimatedGlossaryWrapper.jsx | 3 +- src/js/components/glossary/Glossary.jsx | 9 ++-- src/js/components/glossary/GlossaryHeader.jsx | 3 +- .../components/glossary/GlossarySearchBar.jsx | 7 +-- .../glossary/definition/DefinitionTabs.jsx | 9 ++-- .../definition/GlossaryDefinition.jsx | 5 ++- .../glossary/definition/ItemDefinition.jsx | 9 ++-- .../glossary/definition/MoreResources.jsx | 3 +- .../glossary/definition/SmartLink.jsx | 5 ++- .../glossary/definition/TabItem.jsx | 9 ++-- .../glossary/noResults/NoResults.jsx | 5 ++- .../glossary/search/GlossarySearchResults.jsx | 7 +-- .../glossary/search/ResultGroup.jsx | 9 ++-- .../components/glossary/search/ResultItem.jsx | 7 +-- .../components/homepage/CategorySection.jsx | 6 +-- .../components/homepage/LinksSectionBox.jsx | 11 ++--- .../categoryMap/BudgetLabel.jsx | 17 ++++---- .../visualizations/categoryMap/BudgetLine.jsx | 11 ++--- .../categoryMap/CategoryMap.jsx | 7 +-- .../categoryMap/CategoryMapCell.jsx | 23 +++++----- .../categoryMap/CategoryMapTooltip.jsx | 15 ++++--- .../homepage/visualizations/geo/MapList.jsx | 5 ++- .../visualizations/geo/MapToggleList.jsx | 5 ++- .../visualizations/geo/MapVisualization.jsx | 7 +-- .../geo/MapVisualizationWrapper.jsx | 3 +- .../geo/cells/MapListHeaderCell.jsx | 13 +++--- .../geo/tooltips/GeoCapitaTooltip.jsx | 17 ++++---- .../geo/tooltips/GeoTotalTooltip.jsx | 13 +++--- .../BudgetFunctions/BudgetFunctionCell.jsx | 43 ++++++++++--------- .../BudgetFunctions/BudgetFunctions.jsx | 11 ++--- .../BudgetSubfunctions/BudgetSubfunctions.jsx | 23 +++++----- .../BudgetSubfunctionsDescription.jsx | 11 ++--- .../BudgetSubfunctionsMap.jsx | 11 ++--- .../BudgetSubfunctionsNavigation.jsx | 19 ++++---- .../MinimizedBudgetFunctions.jsx | 17 ++++---- .../MinimizedBudgetFunctionsCell.jsx | 23 +++++----- .../MinimizedBudgetFunctionsTooltip.jsx | 13 +++--- .../visualizations/treemap/TreeMap.jsx | 15 ++++--- .../visualizations/treemap/TreeMapLabel.jsx | 11 ++--- .../visualizations/treemap/TreeMapLine.jsx | 7 +-- .../visualizations/treemap/TreeMapTooltip.jsx | 27 ++++++------ src/js/components/search/SearchPage.jsx | 3 +- src/js/components/search/SearchResults.jsx | 11 ++--- src/js/components/search/SearchSidebar.jsx | 3 +- .../search/filters/agency/Agency.jsx | 9 ++-- .../filters/agency/SelectedAgencies.jsx | 7 +-- .../search/filters/agency/ShownAgency.jsx | 9 ++-- .../filters/awardAmount/AwardAmountItem.jsx | 9 ++-- .../filters/awardAmount/AwardAmountSearch.jsx | 7 +-- .../awardAmount/SpecificAwardAmountItem.jsx | 3 +- .../search/filters/awardID/AwardIDSearch.jsx | 5 ++- .../filters/awardID/SelectedAwardIDs.jsx | 5 ++- .../search/filters/awardID/ShownAwardID.jsx | 5 ++- .../filters/awardType/AwardExpandButton.jsx | 7 +-- .../search/filters/awardType/AwardType.jsx | 7 +-- .../budgetCategory/BudgetCategoryOCSearch.jsx | 7 +-- .../budgetCategory/BudgetCategorySearch.jsx | 9 ++-- .../budgetCategory/ObjectClassItem.jsx | 9 ++-- .../SelectedBudgetFunctions.jsx | 5 ++- .../SelectedFederalAccounts.jsx | 5 ++- .../budgetCategory/ShownBudgetFunction.jsx | 5 ++- .../budgetCategory/ShownFederalAccount.jsx | 5 ++- .../search/filters/keyword/Keyword.jsx | 7 +-- .../search/filters/location/CountryType.jsx | 7 +-- .../filters/location/LocationSearch.jsx | 7 +-- .../filters/location/SelectedLocations.jsx | 5 ++- .../search/filters/location/ShownLocation.jsx | 5 ++- .../filters/recipient/RecipientSearch.jsx | 13 +++--- .../filters/recipient/RecipientToggle.jsx | 7 +-- .../filters/recipient/RecipientType.jsx | 5 ++- .../recipient/SelectedRecipientLocations.jsx | 5 ++- .../filters/recipient/SelectedRecipients.jsx | 5 ++- .../filters/recipient/ShownRecipient.jsx | 5 ++- .../recipient/ShownRecipientLocation.jsx | 5 ++- .../filters/timePeriod/AllFiscalYears.jsx | 7 +-- .../search/filters/timePeriod/DateRange.jsx | 13 +++--- .../filters/timePeriod/DateRangeError.jsx | 5 ++- .../search/filters/timePeriod/FiscalYear.jsx | 9 ++-- .../search/filters/timePeriod/TimePeriod.jsx | 21 ++++----- .../components/search/header/FormatItem.jsx | 11 ++--- .../components/search/header/SearchHeader.jsx | 5 ++- .../search/mobile/MobileFilterHeader.jsx | 5 ++- .../search/mobile/MobileFilters.jsx | 7 +-- .../search/modals/DownloadLocation.jsx | 3 +- .../components/search/modals/ExtraModal.jsx | 13 +++--- .../search/table/ResultsColumnOption.jsx | 9 ++-- .../table/ResultsColumnVisibleOption.jsx | 21 ++++----- .../search/table/ResultsSelectColumns.jsx | 9 ++-- .../components/search/table/ResultsTable.jsx | 15 ++++--- .../search/table/ResultsTableMessage.jsx | 3 +- .../search/table/ResultsTablePicker.jsx | 7 +-- .../search/table/ResultsTablePickerOption.jsx | 13 +++--- .../search/table/ResultsTableSection.jsx | 21 ++++----- .../search/table/ResultsTableTabItem.jsx | 11 ++--- .../search/table/ResultsTableTabs.jsx | 7 +-- .../table/cells/ResultsTableAwardIdCell.jsx | 11 ++--- .../table/cells/ResultsTableGenericCell.jsx | 9 ++-- .../table/cells/ResultsTableHeaderCell.jsx | 13 +++--- .../search/topFilterBar/TopFilterBar.jsx | 9 ++-- .../search/topFilterBar/TopFilterItem.jsx | 7 +-- .../filterGroups/AgencyFilterGroup.jsx | 5 ++- .../filterGroups/AwardAmountFilterGroup.jsx | 5 ++- .../filterGroups/AwardIDFilterGroup.jsx | 5 ++- .../filterGroups/AwardTypeFilterGroup.jsx | 5 ++- .../filterGroups/BaseTopFilterGroup.jsx | 7 +-- .../BudgetCategoryFilterGroup.jsx | 5 ++- .../filterGroups/KeywordFilterGroup.jsx | 5 ++- .../filterGroups/LocationFilterGroup.jsx | 7 +-- .../filterGroups/RecipientFilterGroup.jsx | 5 ++- .../filterGroups/RecipientTypeFilterGroup.jsx | 5 ++- .../filterGroups/TimePeriodDRFilterGroup.jsx | 5 ++- .../filterGroups/TimePeriodFYFilterGroup.jsx | 5 ++- .../geo/GeoVisualizationScopeButton.jsx | 9 ++-- .../geo/GeoVisualizationSection.jsx | 9 ++-- .../geo/GeoVisualizationTooltip.jsx | 13 +++--- .../search/visualizations/geo/MapLegend.jsx | 5 ++- .../visualizations/geo/MapLegendItem.jsx | 5 ++- .../search/visualizations/geo/MapWrapper.jsx | 15 ++++--- .../search/visualizations/geo/map/MapBox.jsx | 9 ++-- .../visualizations/rank/RankVisualization.jsx | 11 ++--- .../rank/RankVisualizationChartMessage.jsx | 3 +- .../rank/RankVisualizationScopeButton.jsx | 11 ++--- .../rank/RankVisualizationTitle.jsx | 7 +-- .../rank/RankVisualizationTooltip.jsx | 11 ++--- .../visualizations/rank/chart/ChartBar.jsx | 25 +++++------ .../visualizations/rank/chart/ChartGroup.jsx | 17 ++++---- .../rank/chart/HorizontalChart.jsx | 29 +++++++------ .../rank/chart/HorizontalXAxis.jsx | 9 ++-- .../rank/chart/HorizontalXLabel.jsx | 11 ++--- .../rank/chart/HorizontalYAxis.jsx | 9 ++-- .../sections/RankVisualizationSection.jsx | 13 +++--- .../rank/sections/SpendingByAgencySection.jsx | 9 ++-- .../sections/SpendingByCategorySection.jsx | 5 ++- .../SpendingByIndustryCodeSection.jsx | 5 ++- .../sections/SpendingByRecipientSection.jsx | 5 ++- .../visualizations/time/TimeVisualization.jsx | 13 +++--- .../time/TimeVisualizationChartMessage.jsx | 3 +- .../time/TimeVisualizationPeriodButton.jsx | 9 ++-- .../time/TimeVisualizationSection.jsx | 3 +- .../time/TimeVisualizationTooltip.jsx | 7 +-- .../visualizations/time/chart/BarChart.jsx | 19 ++++---- .../time/chart/BarChartLegend.jsx | 3 +- .../time/chart/BarChartLegendItem.jsx | 7 +-- .../visualizations/time/chart/BarItem.jsx | 27 ++++++------ .../visualizations/time/chart/BarXAxis.jsx | 9 ++-- .../time/chart/BarXAxisItem.jsx | 7 +-- .../visualizations/time/chart/BarYAxis.jsx | 11 ++--- .../time/chart/BarYAxisItem.jsx | 11 ++--- .../sharedComponents/DatePicker.jsx | 17 ++++---- src/js/components/sharedComponents/Error.jsx | 5 ++- .../FloatingGlossaryButton.jsx | 3 +- .../IBTable/components/HeaderCell.jsx | 7 +-- .../IBTable/components/HeaderRow.jsx | 9 ++-- .../IBTable/components/Table.jsx | 5 ++- .../IBTable/components/TableBody.jsx | 19 ++++---- .../IBTable/components/TableCell.jsx | 11 ++--- .../IBTable/components/TableRow.jsx | 11 ++--- .../components/sharedComponents/ScrollTo.jsx | 13 +++--- .../sharedComponents/ToggleButton.jsx | 9 ++-- .../autocomplete/Autocomplete.jsx | 25 +++++------ .../autocomplete/Suggestion.jsx | 11 ++--- .../autocomplete/SuggestionHolder.jsx | 11 ++--- .../sharedComponents/autocomplete/Warning.jsx | 5 ++- .../checkbox/CheckboxExpandButton.jsx | 7 +-- .../checkbox/CollapsedCheckboxType.jsx | 15 ++++--- .../checkbox/PrimaryCheckboxType.jsx | 19 ++++---- .../checkbox/SecondaryCheckboxType.jsx | 15 ++++--- .../checkbox/SingleCheckboxType.jsx | 15 ++++--- .../filterSidebar/FilterExpandButton.jsx | 11 ++--- .../filterSidebar/FilterOption.jsx | 9 ++-- .../filterSidebar/FilterSidebar.jsx | 7 +-- .../header/NavBarGlossaryLink.jsx | 3 +- .../sharedComponents/metaTags/MetaTags.jsx | 27 ++++++------ src/js/components/testStyles/IconsExample.jsx | 5 ++- .../testStyles/TestStyleIconItem.jsx | 5 ++- .../containers/account/AccountContainer.jsx | 7 +-- .../account/awards/AccountAwardsContainer.jsx | 19 ++++---- .../AccountAwardsHeaderCellContainer.jsx | 3 +- .../filters/AccountObjectClassContainer.jsx | 3 +- .../AccountProgramActivityContainer.jsx | 7 +-- .../filters/AccountTimePeriodContainer.jsx | 11 ++--- .../AccountTopFilterBarContainer.jsx | 5 ++- .../AccountRankVisualizationContainer.jsx | 5 ++- .../AccountTimeVisualizationContainer.jsx | 6 +-- src/js/containers/agency/AgencyContainer.jsx | 7 +-- .../agency/AgencyFooterContainer.jsx | 7 +-- .../visualizations/ObjectClassContainer.jsx | 5 ++- .../visualizations/ObligatedContainer.jsx | 7 +-- .../visualizations/RecipientContainer.jsx | 5 ++- src/js/containers/award/AwardContainer.jsx | 5 ++- .../award/subawards/SubawardsContainer.jsx | 13 +++--- .../AssistanceTransactionsTableContainer.jsx | 13 +++--- .../ContractTransactionsTableContainer.jsx | 13 +++--- .../table/FinancialSystemTableContainer.jsx | 17 ++++---- .../table/LoanTransactionsTableContainer.jsx | 13 +++--- .../GlossaryButtonWrapperContainer.jsx | 5 ++- .../containers/glossary/GlossaryContainer.jsx | 11 ++--- src/js/containers/search/SearchContainer.jsx | 9 ++-- .../search/filters/AgencyContainer.jsx | 5 ++- .../search/filters/AgencyListContainer.jsx | 15 ++++--- .../search/filters/AwardTypeContainer.jsx | 5 ++- .../search/filters/KeywordContainer.jsx | 5 ++- .../search/filters/TimePeriodContainer.jsx | 11 ++--- .../AwardAmountSearchContainer.jsx | 3 +- .../filters/awardID/AwardIDListContainer.jsx | 15 ++++--- .../awardID/AwardIDSearchContainer.jsx | 3 +- .../BudgetCategoryAccountContainer.jsx | 9 ++-- .../BudgetCategoryFunctionContainer.jsx | 9 ++-- .../BudgetCategoryOCContainer.jsx | 5 ++- .../BudgetCategorySearchContainer.jsx | 8 ++-- .../location/LocationListContainer.jsx | 11 ++--- .../location/LocationSearchContainer.jsx | 5 ++- .../recipient/RecipientLocationContainer.jsx | 11 ++--- .../recipient/RecipientNameDUNSContainer.jsx | 9 ++-- .../recipient/RecipientSearchContainer.jsx | 11 ++--- .../search/modals/ExtraModalContainer.jsx | 5 ++- .../search/table/ResultsTableContainer.jsx | 35 +++++++-------- .../table/ResultsTableHeaderCellContainer.jsx | 3 +- .../topFilterBar/TopFilterBarContainer.jsx | 5 ++- .../geo/GeoVisualizationSectionContainer.jsx | 5 ++- .../RankVisualizationWrapperContainer.jsx | 3 +- ...ByAwardingAgencyVisualizationContainer.jsx | 9 ++-- .../SpendingByCFDAVisualizationContainer.jsx | 9 ++-- ...egoryRankVisualizationSectionContainer.jsx | 9 ++-- ...gByFundingAgencyVisualizationContainer.jsx | 9 ++-- ...ngByIndustryCodeVisualizationContainer.jsx | 9 ++-- ...ndingByRecipientVisualizationContainer.jsx | 9 ++-- .../TimeVisualizationSectionContainer.jsx | 5 ++- 325 files changed, 1666 insertions(+), 1347 deletions(-) diff --git a/criticalVersions.json b/criticalVersions.json index 95ef01056e..5c1f492e21 100644 --- a/criticalVersions.json +++ b/criticalVersions.json @@ -1,4 +1,4 @@ { - "react": "15.4.2", - "redux": "3.6.0" + "react": "15.6.1", + "redux": "3.7.1" } \ No newline at end of file diff --git a/package.json b/package.json index 5d553fe9e7..c220e264a0 100644 --- a/package.json +++ b/package.json @@ -122,26 +122,27 @@ "mousetrap": "^1.6.1", "node-uuid": "^1.4.7", "path-to-regexp": "^1.7.0", + "prop-types": "15.5.10", "q": "^1.4.1", "query-string": "^4.3.4", "r-dom": "^2.3.2", - "react": "15.4.2", + "react": "15.6.1", "react-addons-perf": "15.4.2", - "react-addons-test-utils": "15.4.2", - "react-addons-update": "^15.4.2", + "react-addons-test-utils": "15.6.0", + "react-addons-update": "15.6.0", "react-aria-modal": "^2.6.0", "react-custom-scrollbars": "^4.1.2", "react-day-picker": "^3.1.1", "react-dnd": "^2.4.0", "react-dnd-html5-backend": "^2.4.1", - "react-dom": "15.4.2", + "react-dom": "15.6.1", "react-ga": "^2.1.2", "react-helmet": "^5.0.0", "react-map-gl": "^2.0.2", "react-markdown": "^2.5.0", - "react-redux": "4.4.6", + "react-redux": "5.0.5", "react-transition-group": "^1.1.2", - "redux": "3.6.0", + "redux": "3.7.1", "redux-perf-middleware": "^1.2.2", "svg4everybody": "^2.0.3", "tinycolor2": "^1.3.0", diff --git a/src/js/components/about/NextStepsBox.jsx b/src/js/components/about/NextStepsBox.jsx index 71a23424ea..10b39a1aa5 100644 --- a/src/js/components/about/NextStepsBox.jsx +++ b/src/js/components/about/NextStepsBox.jsx @@ -4,18 +4,19 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as AboutIcons from 'components/sharedComponents/icons/about/AboutIcons'; const propTypes = { - icon: React.PropTypes.string, - sectionTitle: React.PropTypes.string, - sectionText: React.PropTypes.string, - linkText: React.PropTypes.string, - linkUrl: React.PropTypes.string, - iconClass: React.PropTypes.string, - ariaLabel: React.PropTypes.string, - title: React.PropTypes.string + icon: PropTypes.string, + sectionTitle: PropTypes.string, + sectionText: PropTypes.string, + linkText: PropTypes.string, + linkUrl: PropTypes.string, + iconClass: PropTypes.string, + ariaLabel: PropTypes.string, + title: PropTypes.string }; export default class NextStepsBox extends React.Component { diff --git a/src/js/components/account/Account.jsx b/src/js/components/account/Account.jsx index af9ac3c681..ee7ce3fa9c 100644 --- a/src/js/components/account/Account.jsx +++ b/src/js/components/account/Account.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MetaTagHelper from 'helpers/metaTagHelper'; @@ -17,7 +18,7 @@ import SearchSidebar from './SearchSidebar'; import SearchResults from './SearchResults'; const propTypes = { - account: React.PropTypes.object + account: PropTypes.object }; export default class Account extends React.Component { diff --git a/src/js/components/account/AccountHeader.jsx b/src/js/components/account/AccountHeader.jsx index 43d8315c24..09261744ec 100644 --- a/src/js/components/account/AccountHeader.jsx +++ b/src/js/components/account/AccountHeader.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import InfoSnippet from '../award/InfoSnippet'; import MoreHeaderOptions from '../award/MoreHeaderOptions'; const propTypes = { - account: React.PropTypes.object + account: PropTypes.object }; export default class AccountHeader extends React.Component { diff --git a/src/js/components/account/AccountOverview.jsx b/src/js/components/account/AccountOverview.jsx index 251ae76f3f..db52f3e9b4 100644 --- a/src/js/components/account/AccountOverview.jsx +++ b/src/js/components/account/AccountOverview.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import * as FiscalYearHelper from 'helpers/fiscalYearHelper'; import SankeyVisualization from './visualizations/sankey/SankeyVisualization'; const propTypes = { - account: React.PropTypes.object + account: PropTypes.object }; export default class AccountOverview extends React.Component { diff --git a/src/js/components/account/InvalidAccount.jsx b/src/js/components/account/InvalidAccount.jsx index ad9998cac2..3f62c18b02 100644 --- a/src/js/components/account/InvalidAccount.jsx +++ b/src/js/components/account/InvalidAccount.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Header from '../sharedComponents/header/Header'; import Footer from '../sharedComponents/Footer'; import Error from '../sharedComponents/Error'; const propTypes = { - account: React.PropTypes.object + account: PropTypes.object }; export default class InvalidAccount extends React.Component { diff --git a/src/js/components/account/LoadingAccount.jsx b/src/js/components/account/LoadingAccount.jsx index 129bfaf62e..3ad2d16c2e 100644 --- a/src/js/components/account/LoadingAccount.jsx +++ b/src/js/components/account/LoadingAccount.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Header from '../sharedComponents/header/Header'; import Footer from '../sharedComponents/Footer'; import Error from '../sharedComponents/Error'; const propTypes = { - account: React.PropTypes.object + account: PropTypes.object }; export default class LoadingAccount extends React.Component { diff --git a/src/js/components/account/awards/AccountAwardsSection.jsx b/src/js/components/account/awards/AccountAwardsSection.jsx index dbd7fd20cb..7024409ccf 100644 --- a/src/js/components/account/awards/AccountAwardsSection.jsx +++ b/src/js/components/account/awards/AccountAwardsSection.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ResultsTableTabs from 'components/search/table/ResultsTableTabs'; import ResultsTable from 'components/search/table/ResultsTable'; @@ -13,11 +14,11 @@ import AccountAwardsHeaderCellContainer from 'containers/account/awards/AccountAwardsHeaderCellContainer'; const propTypes = { - inFlight: React.PropTypes.bool, - tableTypes: React.PropTypes.array, - currentType: React.PropTypes.string, - switchTab: React.PropTypes.func, - results: React.PropTypes.array + inFlight: PropTypes.bool, + tableTypes: PropTypes.array, + currentType: PropTypes.string, + switchTab: PropTypes.func, + results: PropTypes.array }; export default class AccountAwardsSection extends React.Component { diff --git a/src/js/components/account/filters/objectClass/ObjectClassFilter.jsx b/src/js/components/account/filters/objectClass/ObjectClassFilter.jsx index 4d6c683c4a..beeb750d47 100644 --- a/src/js/components/account/filters/objectClass/ObjectClassFilter.jsx +++ b/src/js/components/account/filters/objectClass/ObjectClassFilter.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { OrderedSet } from 'immutable'; import { objectClassDefinitions } from 'dataMapping/search/budgetCategory'; @@ -11,8 +12,8 @@ import { objectClassDefinitions } from 'dataMapping/search/budgetCategory'; import PrimaryCheckboxType from 'components/sharedComponents/checkbox/PrimaryCheckboxType'; const propTypes = { - selectedCodes: React.PropTypes.instanceOf(OrderedSet), - updateFilter: React.PropTypes.func + selectedCodes: PropTypes.instanceOf(OrderedSet), + updateFilter: PropTypes.func }; export default class ObjectClassFilter extends React.Component { diff --git a/src/js/components/account/filters/programActivity/ProgramActivityFilter.jsx b/src/js/components/account/filters/programActivity/ProgramActivityFilter.jsx index bc73f89897..922c9b364a 100644 --- a/src/js/components/account/filters/programActivity/ProgramActivityFilter.jsx +++ b/src/js/components/account/filters/programActivity/ProgramActivityFilter.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { OrderedSet } from 'immutable'; import { sortBy, keyBy } from 'lodash'; @@ -11,11 +12,11 @@ import * as Icons from 'components/sharedComponents/icons/Icons'; import PrimaryCheckboxType from 'components/sharedComponents/checkbox/PrimaryCheckboxType'; const propTypes = { - selectedProgramActivities: React.PropTypes.instanceOf(OrderedSet), - availableProgramActivities: React.PropTypes.array, - updateFilter: React.PropTypes.func, - noResults: React.PropTypes.bool, - inFlight: React.PropTypes.bool + selectedProgramActivities: PropTypes.instanceOf(OrderedSet), + availableProgramActivities: PropTypes.array, + updateFilter: PropTypes.func, + noResults: PropTypes.bool, + inFlight: PropTypes.bool }; const defaultShown = 10; diff --git a/src/js/components/account/topFilterBar/filterGroups/ObjectClassFilterGroup.jsx b/src/js/components/account/topFilterBar/filterGroups/ObjectClassFilterGroup.jsx index a2cb644e65..24e4c92c15 100644 --- a/src/js/components/account/topFilterBar/filterGroups/ObjectClassFilterGroup.jsx +++ b/src/js/components/account/topFilterBar/filterGroups/ObjectClassFilterGroup.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { objectClassDefinitions } from 'dataMapping/search/budgetCategory'; import BaseTopFilterGroup from 'components/search/topFilterBar/filterGroups/BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class ObjectClassFilterGroup extends React.Component { diff --git a/src/js/components/account/topFilterBar/filterGroups/ProgramActivityFilterGroup.jsx b/src/js/components/account/topFilterBar/filterGroups/ProgramActivityFilterGroup.jsx index 4e21e8f21d..973d537d2c 100644 --- a/src/js/components/account/topFilterBar/filterGroups/ProgramActivityFilterGroup.jsx +++ b/src/js/components/account/topFilterBar/filterGroups/ProgramActivityFilterGroup.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { find } from 'lodash'; import BaseTopFilterGroup from 'components/search/topFilterBar/filterGroups/BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class ProgramActivityFilterGroup extends React.Component { diff --git a/src/js/components/account/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx b/src/js/components/account/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx index 04690cd937..93981b3b87 100644 --- a/src/js/components/account/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx +++ b/src/js/components/account/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BaseTopFilterGroup from 'components/search/topFilterBar/filterGroups/BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class TimePeriodDRFilterGroup extends React.Component { diff --git a/src/js/components/account/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx b/src/js/components/account/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx index 644e5a5ca1..70a6407be3 100644 --- a/src/js/components/account/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx +++ b/src/js/components/account/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as FiscalYearHelper from 'helpers/fiscalYearHelper'; import BaseTopFilterGroup from 'components/search/topFilterBar/filterGroups/BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class TimePeriodFYFilterGroup extends React.Component { diff --git a/src/js/components/account/visualizations/rank/AccountRankVisualizationSection.jsx b/src/js/components/account/visualizations/rank/AccountRankVisualizationSection.jsx index 466d7a4f78..f59fc7871b 100644 --- a/src/js/components/account/visualizations/rank/AccountRankVisualizationSection.jsx +++ b/src/js/components/account/visualizations/rank/AccountRankVisualizationSection.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle, min } from 'lodash'; import * as Icons from 'components/sharedComponents/icons/Icons'; @@ -13,14 +14,14 @@ import RankVisualizationScopeButton from 'components/search/visualizations/rank/RankVisualizationScopeButton'; const propTypes = { - categoryScope: React.PropTypes.string, - changeScope: React.PropTypes.func, - nextPage: React.PropTypes.func, - previousPage: React.PropTypes.func, - hasNextPage: React.PropTypes.bool, - hasPreviousPage: React.PropTypes.bool, - page: React.PropTypes.number, - loading: React.PropTypes.bool + categoryScope: PropTypes.string, + changeScope: PropTypes.func, + nextPage: PropTypes.func, + previousPage: PropTypes.func, + hasNextPage: PropTypes.bool, + hasPreviousPage: PropTypes.bool, + page: PropTypes.number, + loading: PropTypes.bool }; export default class AccountRankVisualizationSection extends React.Component { diff --git a/src/js/components/account/visualizations/sankey/SankeyVisualization.jsx b/src/js/components/account/visualizations/sankey/SankeyVisualization.jsx index 5ed82dc937..c98e4d47a6 100644 --- a/src/js/components/account/visualizations/sankey/SankeyVisualization.jsx +++ b/src/js/components/account/visualizations/sankey/SankeyVisualization.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import SankeyMessage from './components/SankeyMessage'; import SankeyVisualizationHorizontal from './SankeyVisualizationHorizontal'; import SankeyVisualizationVertical from './SankeyVisualizationVertical'; const propTypes = { - width: React.PropTypes.number, - fyAvailable: React.PropTypes.bool + width: PropTypes.number, + fyAvailable: PropTypes.bool }; export default class SankeyVisualization extends React.Component { diff --git a/src/js/components/account/visualizations/sankey/SankeyVisualizationHorizontal.jsx b/src/js/components/account/visualizations/sankey/SankeyVisualizationHorizontal.jsx index 99be44fee4..422f147301 100644 --- a/src/js/components/account/visualizations/sankey/SankeyVisualizationHorizontal.jsx +++ b/src/js/components/account/visualizations/sankey/SankeyVisualizationHorizontal.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -14,9 +15,9 @@ import DirectionLabel from './components/DirectionLabel'; import SankeyDisclosures from './components/SankeyDisclosures'; const propTypes = { - width: React.PropTypes.number, - height: React.PropTypes.number, - amounts: React.PropTypes.object + width: PropTypes.number, + height: PropTypes.number, + amounts: PropTypes.object }; export default class SankeyVisualizationHorizontal extends React.Component { diff --git a/src/js/components/account/visualizations/sankey/SankeyVisualizationVertical.jsx b/src/js/components/account/visualizations/sankey/SankeyVisualizationVertical.jsx index b69873427b..6c850306b8 100644 --- a/src/js/components/account/visualizations/sankey/SankeyVisualizationVertical.jsx +++ b/src/js/components/account/visualizations/sankey/SankeyVisualizationVertical.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -14,8 +15,8 @@ import DirectionLabel from './components/DirectionLabel'; import SankeyDisclosures from './components/SankeyDisclosures'; const propTypes = { - width: React.PropTypes.number, - amounts: React.PropTypes.object + width: PropTypes.number, + amounts: PropTypes.object }; export default class SankeyVisualizationVertical extends React.Component { diff --git a/src/js/components/account/visualizations/sankey/components/DirectionLabel.jsx b/src/js/components/account/visualizations/sankey/components/DirectionLabel.jsx index dd43fdad94..be8ff6fa3e 100644 --- a/src/js/components/account/visualizations/sankey/components/DirectionLabel.jsx +++ b/src/js/components/account/visualizations/sankey/components/DirectionLabel.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - paddingX: React.PropTypes.number, - title: React.PropTypes.string, - children: React.PropTypes.element + x: PropTypes.number, + y: PropTypes.number, + paddingX: PropTypes.number, + title: PropTypes.string, + children: PropTypes.element }; const defaultProps = { diff --git a/src/js/components/account/visualizations/sankey/components/ItemLabel.jsx b/src/js/components/account/visualizations/sankey/components/ItemLabel.jsx index 15763fc3d9..217ba430ae 100644 --- a/src/js/components/account/visualizations/sankey/components/ItemLabel.jsx +++ b/src/js/components/account/visualizations/sankey/components/ItemLabel.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - hide: React.PropTypes.bool, - title: React.PropTypes.string, - value: React.PropTypes.string + x: PropTypes.number, + y: PropTypes.number, + hide: PropTypes.bool, + title: PropTypes.string, + value: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/account/visualizations/sankey/components/ItemLegend.jsx b/src/js/components/account/visualizations/sankey/components/ItemLegend.jsx index 25f4bb9432..2a536cad4d 100644 --- a/src/js/components/account/visualizations/sankey/components/ItemLegend.jsx +++ b/src/js/components/account/visualizations/sankey/components/ItemLegend.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - color: React.PropTypes.string, - x: React.PropTypes.number, - y: React.PropTypes.number, - hide: React.PropTypes.bool, - title: React.PropTypes.string, - value: React.PropTypes.string + color: PropTypes.string, + x: PropTypes.number, + y: PropTypes.number, + hide: PropTypes.bool, + title: PropTypes.string, + value: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/account/visualizations/sankey/components/SankeyBar.jsx b/src/js/components/account/visualizations/sankey/components/SankeyBar.jsx index c755fe5c05..80fb60fb4c 100644 --- a/src/js/components/account/visualizations/sankey/components/SankeyBar.jsx +++ b/src/js/components/account/visualizations/sankey/components/SankeyBar.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - width: React.PropTypes.number, - height: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - description: React.PropTypes.string, - color: React.PropTypes.string + width: PropTypes.number, + height: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + description: PropTypes.string, + color: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/account/visualizations/sankey/components/SankeyDisclosures.jsx b/src/js/components/account/visualizations/sankey/components/SankeyDisclosures.jsx index ffd83bfe6e..8cd8bad22c 100644 --- a/src/js/components/account/visualizations/sankey/components/SankeyDisclosures.jsx +++ b/src/js/components/account/visualizations/sankey/components/SankeyDisclosures.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - items: React.PropTypes.array + items: PropTypes.array }; export default class SankeyDisclosures extends React.Component { diff --git a/src/js/components/account/visualizations/sankey/components/SankeyFlow.jsx b/src/js/components/account/visualizations/sankey/components/SankeyFlow.jsx index ed245d6e98..3d1b42f52e 100644 --- a/src/js/components/account/visualizations/sankey/components/SankeyFlow.jsx +++ b/src/js/components/account/visualizations/sankey/components/SankeyFlow.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { interpolateNumber } from 'd3-interpolate'; const propTypes = { - height: React.PropTypes.number, - description: React.PropTypes.string, - style: React.PropTypes.object + height: PropTypes.number, + description: PropTypes.string, + style: PropTypes.object }; const defaultProps = { diff --git a/src/js/components/account/visualizations/sankey/components/SankeyFlowVertical.jsx b/src/js/components/account/visualizations/sankey/components/SankeyFlowVertical.jsx index 92dc03fd02..64ac884fac 100644 --- a/src/js/components/account/visualizations/sankey/components/SankeyFlowVertical.jsx +++ b/src/js/components/account/visualizations/sankey/components/SankeyFlowVertical.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { interpolateNumber } from 'd3-interpolate'; const propTypes = { - width: React.PropTypes.number, - description: React.PropTypes.string, - style: React.PropTypes.object + width: PropTypes.number, + description: PropTypes.string, + style: PropTypes.object }; const defaultProps = { diff --git a/src/js/components/account/visualizations/sankey/components/SankeyMessage.jsx b/src/js/components/account/visualizations/sankey/components/SankeyMessage.jsx index 79f97c87b0..9f4bdfb5d4 100644 --- a/src/js/components/account/visualizations/sankey/components/SankeyMessage.jsx +++ b/src/js/components/account/visualizations/sankey/components/SankeyMessage.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - message: React.PropTypes.string + message: PropTypes.string }; export default class SankeyMessage extends React.Component { diff --git a/src/js/components/account/visualizations/time/AccountTimeVisualizationPeriodButton.jsx b/src/js/components/account/visualizations/time/AccountTimeVisualizationPeriodButton.jsx index 6a3a7a8154..8b7928482b 100644 --- a/src/js/components/account/visualizations/time/AccountTimeVisualizationPeriodButton.jsx +++ b/src/js/components/account/visualizations/time/AccountTimeVisualizationPeriodButton.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - active: React.PropTypes.bool, - value: React.PropTypes.string, - label: React.PropTypes.string, - changePeriod: React.PropTypes.func + active: PropTypes.bool, + value: PropTypes.string, + label: PropTypes.string, + changePeriod: PropTypes.func }; export default class AccountTimeVisualizationPeriodButton extends React.Component { diff --git a/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx b/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx index 7b03f47cd5..82dcea1bb8 100644 --- a/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx +++ b/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import AccountTimeVisualizationPeriodButton from './AccountTimeVisualizationPeriodButton'; @@ -11,10 +12,10 @@ import AccountTimeVisualizationPeriodButton from './AccountTimeVisualizationPeri import TimeVisualization from './TimeVisualization'; const propTypes = { - data: React.PropTypes.object, - visualizationPeriod: React.PropTypes.string, - changePeriod: React.PropTypes.func, - hasFilteredObligated: React.PropTypes.bool + data: PropTypes.object, + visualizationPeriod: PropTypes.string, + changePeriod: PropTypes.func, + hasFilteredObligated: PropTypes.bool }; export default class AccountTimeVisualizationSection extends React.Component { diff --git a/src/js/components/account/visualizations/time/TimeVisualization.jsx b/src/js/components/account/visualizations/time/TimeVisualization.jsx index 4ad63aaba1..26fd2a1e63 100644 --- a/src/js/components/account/visualizations/time/TimeVisualization.jsx +++ b/src/js/components/account/visualizations/time/TimeVisualization.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ChartMessage from 'components/search/visualizations/time/TimeVisualizationChartMessage'; import BarChartStacked from './chart/BarChartStacked'; @@ -28,13 +29,13 @@ const defaultProps = { /* eslint-disable react/no-unused-prop-types */ // allow unused prop types. they are passed to child components, but documented here const propTypes = { - width: React.PropTypes.number, - height: React.PropTypes.number, - groups: React.PropTypes.array, - xSeries: React.PropTypes.array, - ySeries: React.PropTypes.array, - loading: React.PropTypes.bool, - hasFilteredObligated: React.PropTypes.bool + width: PropTypes.number, + height: PropTypes.number, + groups: PropTypes.array, + xSeries: PropTypes.array, + ySeries: PropTypes.array, + loading: PropTypes.bool, + hasFilteredObligated: PropTypes.bool }; /* eslint-enable react/no-unused-prop-types */ diff --git a/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx b/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx index 6d7b6d4cde..59303c9302 100644 --- a/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx +++ b/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { scaleBand, scaleLinear } from 'd3-scale'; import { isEqual, min, max, mean, forEach, sum } from 'lodash'; @@ -18,17 +19,17 @@ import OutlayItem from './OutlayItem'; /* eslint-disable react/no-unused-prop-types */ // we're catching the props before they're fully set, so eslint thinks these props are unused const propTypes = { - groups: React.PropTypes.array, - width: React.PropTypes.number, - height: React.PropTypes.number, - allY: React.PropTypes.array, - xSeries: React.PropTypes.array, - ySeries: React.PropTypes.array, - showTooltip: React.PropTypes.func, - enableHighlight: React.PropTypes.bool, - padding: React.PropTypes.object, - legend: React.PropTypes.array, - hasFilteredObligated: React.PropTypes.bool + groups: PropTypes.array, + width: PropTypes.number, + height: PropTypes.number, + allY: PropTypes.array, + xSeries: PropTypes.array, + ySeries: PropTypes.array, + showTooltip: PropTypes.func, + enableHighlight: PropTypes.bool, + padding: PropTypes.object, + legend: PropTypes.array, + hasFilteredObligated: PropTypes.bool }; /* eslint-enable react/no-unused-prop-types */ diff --git a/src/js/components/account/visualizations/time/chart/OutlayItem.jsx b/src/js/components/account/visualizations/time/chart/OutlayItem.jsx index c2404a1331..9a768f0f05 100644 --- a/src/js/components/account/visualizations/time/chart/OutlayItem.jsx +++ b/src/js/components/account/visualizations/time/chart/OutlayItem.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - width: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - color: React.PropTypes.string + width: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + color: PropTypes.string }; export default class OutlayItem extends React.Component { diff --git a/src/js/components/account/visualizations/time/chart/StackedBarItem.jsx b/src/js/components/account/visualizations/time/chart/StackedBarItem.jsx index f46ca1aaef..5fcccdc01d 100644 --- a/src/js/components/account/visualizations/time/chart/StackedBarItem.jsx +++ b/src/js/components/account/visualizations/time/chart/StackedBarItem.jsx @@ -4,19 +4,20 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - deregisterBar: React.PropTypes.func, - identifier: React.PropTypes.string, - selectBar: React.PropTypes.func, - deselectBar: React.PropTypes.func, - description: React.PropTypes.string, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - height: React.PropTypes.number, - color: React.PropTypes.string, - graphHeight: React.PropTypes.number + deregisterBar: PropTypes.func, + identifier: PropTypes.string, + selectBar: PropTypes.func, + deselectBar: PropTypes.func, + description: PropTypes.string, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + height: PropTypes.number, + color: PropTypes.string, + graphHeight: PropTypes.number }; export default class StackedBarItem extends React.Component { diff --git a/src/js/components/agency/AgencyContent.jsx b/src/js/components/agency/AgencyContent.jsx index 3bd11d2831..5b421e9c08 100644 --- a/src/js/components/agency/AgencyContent.jsx +++ b/src/js/components/agency/AgencyContent.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { find, throttle } from 'lodash'; import jQuery from 'jquery'; @@ -37,7 +38,7 @@ const agencySections = [ ]; const propTypes = { - agency: React.PropTypes.object + agency: PropTypes.object }; export default class AgencyContent extends React.Component { diff --git a/src/js/components/agency/AgencyPage.jsx b/src/js/components/agency/AgencyPage.jsx index daf5f317a2..d66785ec0e 100644 --- a/src/js/components/agency/AgencyPage.jsx +++ b/src/js/components/agency/AgencyPage.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { agencyPageMetaTags } from 'helpers/metaTagHelper'; @@ -19,10 +20,10 @@ import AgencyError from './AgencyError'; import AgencyContent from './AgencyContent'; const propTypes = { - loading: React.PropTypes.bool, - error: React.PropTypes.bool, - id: React.PropTypes.string, - agency: React.PropTypes.object + loading: PropTypes.bool, + error: PropTypes.bool, + id: PropTypes.string, + agency: PropTypes.object }; export default class AgencyPage extends React.Component { diff --git a/src/js/components/agency/footer/AgencyFooter.jsx b/src/js/components/agency/footer/AgencyFooter.jsx index 30185c56b6..a9d450f595 100644 --- a/src/js/components/agency/footer/AgencyFooter.jsx +++ b/src/js/components/agency/footer/AgencyFooter.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - clickedSearch: React.PropTypes.func + clickedSearch: PropTypes.func }; export default class AgencyFooter extends React.Component { diff --git a/src/js/components/agency/header/AgencyHeader.jsx b/src/js/components/agency/header/AgencyHeader.jsx index 070aa3accf..353e6620e2 100644 --- a/src/js/components/agency/header/AgencyHeader.jsx +++ b/src/js/components/agency/header/AgencyHeader.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - account: React.PropTypes.object + account: PropTypes.object }; export default class AgencyHeader extends React.Component { diff --git a/src/js/components/agency/overview/AgencyOverview.jsx b/src/js/components/agency/overview/AgencyOverview.jsx index 1f51b499d4..5b1917ebbf 100644 --- a/src/js/components/agency/overview/AgencyOverview.jsx +++ b/src/js/components/agency/overview/AgencyOverview.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - agency: React.PropTypes.object + agency: PropTypes.object }; export default class AgencyOverview extends React.Component { diff --git a/src/js/components/agency/sidebar/AgencySidebar.jsx b/src/js/components/agency/sidebar/AgencySidebar.jsx index b044b99bfc..fac41bba4a 100644 --- a/src/js/components/agency/sidebar/AgencySidebar.jsx +++ b/src/js/components/agency/sidebar/AgencySidebar.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import SidebarLink from './SidebarLink'; const propTypes = { - active: React.PropTypes.string, - sections: React.PropTypes.array, - jumpToSection: React.PropTypes.func + active: PropTypes.string, + sections: PropTypes.array, + jumpToSection: PropTypes.func }; export default class AgencySidebar extends React.Component { diff --git a/src/js/components/agency/sidebar/SidebarLink.jsx b/src/js/components/agency/sidebar/SidebarLink.jsx index 381e5480b2..eeaa2d5b44 100644 --- a/src/js/components/agency/sidebar/SidebarLink.jsx +++ b/src/js/components/agency/sidebar/SidebarLink.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Router from 'containers/router/Router'; const propTypes = { - section: React.PropTypes.string, - label: React.PropTypes.string, - active: React.PropTypes.string, - onClick: React.PropTypes.func + section: PropTypes.string, + label: PropTypes.string, + active: PropTypes.string, + onClick: PropTypes.func }; export default class SidebarLink extends React.Component { diff --git a/src/js/components/agency/visualizations/objectClass/MajorObjectClasses.jsx b/src/js/components/agency/visualizations/objectClass/MajorObjectClasses.jsx index fc0f95b233..5d09714167 100644 --- a/src/js/components/agency/visualizations/objectClass/MajorObjectClasses.jsx +++ b/src/js/components/agency/visualizations/objectClass/MajorObjectClasses.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { hierarchy, treemap, treemapBinary, treemapSlice } from 'd3-hierarchy'; import { throttle, remove, orderBy, find } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -14,10 +15,10 @@ import ObjectClassCell from './ObjectClassCell'; import ObjectClassTooltip from './ObjectClassTooltip'; const propTypes = { - majorObjectClasses: React.PropTypes.object, - toggleMinorObjectClass: React.PropTypes.func, - showMinorObjectClass: React.PropTypes.bool, - totalObligation: React.PropTypes.number + majorObjectClasses: PropTypes.object, + toggleMinorObjectClass: PropTypes.func, + showMinorObjectClass: PropTypes.bool, + totalObligation: PropTypes.number }; export default class MajorObjectClasses extends React.Component { diff --git a/src/js/components/agency/visualizations/objectClass/MinorObjectClasses.jsx b/src/js/components/agency/visualizations/objectClass/MinorObjectClasses.jsx index a6bdaf09b1..57878ca0a2 100644 --- a/src/js/components/agency/visualizations/objectClass/MinorObjectClasses.jsx +++ b/src/js/components/agency/visualizations/objectClass/MinorObjectClasses.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { hierarchy, treemap, treemapBinary, treemapSlice } from 'd3-hierarchy'; import { throttle, remove, orderBy, find } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -14,10 +15,10 @@ import ObjectClassCell from './ObjectClassCell'; import ObjectClassTooltip from './ObjectClassTooltip'; const propTypes = { - majorObjectClass: React.PropTypes.object, - minorObjectClasses: React.PropTypes.object, - totalObligation: React.PropTypes.number, - totalMinorObligation: React.PropTypes.number + majorObjectClass: PropTypes.object, + minorObjectClasses: PropTypes.object, + totalObligation: PropTypes.number, + totalMinorObligation: PropTypes.number }; export default class MinorObjectClasses extends React.Component { diff --git a/src/js/components/agency/visualizations/objectClass/ObjectClassCell.jsx b/src/js/components/agency/visualizations/objectClass/ObjectClassCell.jsx index 0e103e10e5..6c9d4fa181 100644 --- a/src/js/components/agency/visualizations/objectClass/ObjectClassCell.jsx +++ b/src/js/components/agency/visualizations/objectClass/ObjectClassCell.jsx @@ -4,31 +4,32 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { truncate } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - label: React.PropTypes.string, - value: React.PropTypes.number, - total: React.PropTypes.number, - x0: React.PropTypes.number, - x1: React.PropTypes.number, - y0: React.PropTypes.number, - objectClassID: React.PropTypes.string, - color: React.PropTypes.string, - strokeColor: React.PropTypes.string, - strokeOpacity: React.PropTypes.number, - toggleMinorObjectClass: React.PropTypes.func, - toggleTooltipIn: React.PropTypes.func, - toggleTooltipOut: React.PropTypes.func, - opacity: React.PropTypes.number, - textColor: React.PropTypes.string, - textClass: React.PropTypes.string, - height: React.PropTypes.number, - width: React.PropTypes.number, - labelView: React.PropTypes.string, - percentView: React.PropTypes.string, - clickable: React.PropTypes.bool + label: PropTypes.string, + value: PropTypes.number, + total: PropTypes.number, + x0: PropTypes.number, + x1: PropTypes.number, + y0: PropTypes.number, + objectClassID: PropTypes.string, + color: PropTypes.string, + strokeColor: PropTypes.string, + strokeOpacity: PropTypes.number, + toggleMinorObjectClass: PropTypes.func, + toggleTooltipIn: PropTypes.func, + toggleTooltipOut: PropTypes.func, + opacity: PropTypes.number, + textColor: PropTypes.string, + textClass: PropTypes.string, + height: PropTypes.number, + width: PropTypes.number, + labelView: PropTypes.string, + percentView: PropTypes.string, + clickable: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/agency/visualizations/objectClass/ObjectClassTooltip.jsx b/src/js/components/agency/visualizations/objectClass/ObjectClassTooltip.jsx index cb661ee64b..65d0f88d38 100644 --- a/src/js/components/agency/visualizations/objectClass/ObjectClassTooltip.jsx +++ b/src/js/components/agency/visualizations/objectClass/ObjectClassTooltip.jsx @@ -4,19 +4,20 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - name: React.PropTypes.string, - value: React.PropTypes.string, - description: React.PropTypes.string, - height: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - percentage: React.PropTypes.string, - arrow: React.PropTypes.bool, - showMinorObjectClass: React.PropTypes.bool, - sectionHeight: React.PropTypes.number + name: PropTypes.string, + value: PropTypes.string, + description: PropTypes.string, + height: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + percentage: PropTypes.string, + arrow: PropTypes.bool, + showMinorObjectClass: PropTypes.bool, + sectionHeight: PropTypes.number }; export default class ObjectClassTooltip extends React.Component { diff --git a/src/js/components/agency/visualizations/objectClass/ObjectClassTreeMap.jsx b/src/js/components/agency/visualizations/objectClass/ObjectClassTreeMap.jsx index f13e7cf730..960f3da5ac 100644 --- a/src/js/components/agency/visualizations/objectClass/ObjectClassTreeMap.jsx +++ b/src/js/components/agency/visualizations/objectClass/ObjectClassTreeMap.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle, find } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -13,11 +14,11 @@ import MajorObjectClasses from './MajorObjectClasses'; import MinorObjectClasses from './MinorObjectClasses'; const propTypes = { - majorObjectClasses: React.PropTypes.object, - minorObjectClasses: React.PropTypes.object, - totalObligation: React.PropTypes.number, - totalMinorObligation: React.PropTypes.number, - showMinorObjectClasses: React.PropTypes.func + majorObjectClasses: PropTypes.object, + minorObjectClasses: PropTypes.object, + totalObligation: PropTypes.number, + totalMinorObligation: PropTypes.number, + showMinorObjectClasses: PropTypes.func }; export default class ObjectClassTreeMap extends React.Component { diff --git a/src/js/components/agency/visualizations/obligated/HorizontalBarItem.jsx b/src/js/components/agency/visualizations/obligated/HorizontalBarItem.jsx index 3e8fc420be..c7b6844083 100644 --- a/src/js/components/agency/visualizations/obligated/HorizontalBarItem.jsx +++ b/src/js/components/agency/visualizations/obligated/HorizontalBarItem.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - description: React.PropTypes.string, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - color: React.PropTypes.string + description: PropTypes.string, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + color: PropTypes.string }; export default class HorizontalBarItem extends React.Component { diff --git a/src/js/components/agency/visualizations/obligated/ObligatedGraph.jsx b/src/js/components/agency/visualizations/obligated/ObligatedGraph.jsx index 3e78f68b5f..6825b6e269 100644 --- a/src/js/components/agency/visualizations/obligated/ObligatedGraph.jsx +++ b/src/js/components/agency/visualizations/obligated/ObligatedGraph.jsx @@ -4,19 +4,19 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import BarChartLegend from 'components/search/visualizations/time/chart/BarChartLegend'; import HorizontalBarItem from './HorizontalBarItem'; - const propTypes = { - activeFY: React.PropTypes.string, - reportingFiscalQuarter: React.PropTypes.number, - obligatedAmount: React.PropTypes.number, - budgetAuthority: React.PropTypes.number, - width: React.PropTypes.number, - obligatedText: React.PropTypes.string, - legend: React.PropTypes.array + activeFY: PropTypes.string, + reportingFiscalQuarter: PropTypes.number, + obligatedAmount: PropTypes.number, + budgetAuthority: PropTypes.number, + width: PropTypes.number, + obligatedText: PropTypes.string, + legend: PropTypes.array }; export default class AgencyObligatedGraph extends React.Component { diff --git a/src/js/components/agency/visualizations/obligated/ObligatedVisualization.jsx b/src/js/components/agency/visualizations/obligated/ObligatedVisualization.jsx index cfbad2c420..e0f520d318 100644 --- a/src/js/components/agency/visualizations/obligated/ObligatedVisualization.jsx +++ b/src/js/components/agency/visualizations/obligated/ObligatedVisualization.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import moment from 'moment'; import { convertQuarterToDate } from 'helpers/fiscalYearHelper'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -12,11 +13,11 @@ import { throttle } from 'lodash'; import AgencyObligatedGraph from './ObligatedGraph'; const propTypes = { - activeFY: React.PropTypes.string, - reportingFiscalQuarter: React.PropTypes.number, - agencyName: React.PropTypes.string, - obligatedAmount: React.PropTypes.number, - budgetAuthority: React.PropTypes.number + activeFY: PropTypes.string, + reportingFiscalQuarter: PropTypes.number, + agencyName: PropTypes.string, + obligatedAmount: PropTypes.number, + budgetAuthority: PropTypes.number }; export default class AgencyObligatedAmount extends React.Component { diff --git a/src/js/components/agency/visualizations/recipient/RecipientChart.jsx b/src/js/components/agency/visualizations/recipient/RecipientChart.jsx index a71de1c9c0..f6ee62f5e2 100644 --- a/src/js/components/agency/visualizations/recipient/RecipientChart.jsx +++ b/src/js/components/agency/visualizations/recipient/RecipientChart.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { AngleLeft, AngleRight } from 'components/sharedComponents/icons/Icons'; import HorizontalChart from 'components/search/visualizations/rank/chart/HorizontalChart'; @@ -11,15 +12,15 @@ import HorizontalChart from 'components/search/visualizations/rank/chart/Horizon import RecipientTooltip from './RecipientTooltip'; const propTypes = { - loading: React.PropTypes.bool, - labelSeries: React.PropTypes.array, - dataSeries: React.PropTypes.array, - descriptions: React.PropTypes.array, - width: React.PropTypes.number, - labelWidth: React.PropTypes.number, - page: React.PropTypes.number, - changePage: React.PropTypes.func, - isLastPage: React.PropTypes.bool + loading: PropTypes.bool, + labelSeries: PropTypes.array, + dataSeries: PropTypes.array, + descriptions: PropTypes.array, + width: PropTypes.number, + labelWidth: PropTypes.number, + page: PropTypes.number, + changePage: PropTypes.func, + isLastPage: PropTypes.bool }; const rowHeight = 60; diff --git a/src/js/components/agency/visualizations/recipient/RecipientTooltip.jsx b/src/js/components/agency/visualizations/recipient/RecipientTooltip.jsx index 32918ac47c..eb88f69861 100644 --- a/src/js/components/agency/visualizations/recipient/RecipientTooltip.jsx +++ b/src/js/components/agency/visualizations/recipient/RecipientTooltip.jsx @@ -4,15 +4,16 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isEqual } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - label: React.PropTypes.string, - value: React.PropTypes.number, - y: React.PropTypes.number, - x: React.PropTypes.number + label: PropTypes.string, + value: PropTypes.number, + y: PropTypes.number, + x: PropTypes.number }; export default class RecipientTooltip extends React.Component { diff --git a/src/js/components/agency/visualizations/recipient/RecipientVisualization.jsx b/src/js/components/agency/visualizations/recipient/RecipientVisualization.jsx index 9457ac836b..75acc0c13e 100644 --- a/src/js/components/agency/visualizations/recipient/RecipientVisualization.jsx +++ b/src/js/components/agency/visualizations/recipient/RecipientVisualization.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ChartMessage from 'components/search/visualizations/rank/RankVisualizationChartMessage'; @@ -11,17 +12,17 @@ import ScopeList from './ScopeList'; import RecipientChart from './RecipientChart'; const propTypes = { - loading: React.PropTypes.bool, - isInitialLoad: React.PropTypes.bool, - error: React.PropTypes.bool, - scope: React.PropTypes.string, - changeScope: React.PropTypes.func, - labelSeries: React.PropTypes.array, - dataSeries: React.PropTypes.array, - descriptions: React.PropTypes.array, - page: React.PropTypes.number, - isLastPage: React.PropTypes.bool, - changePage: React.PropTypes.func + loading: PropTypes.bool, + isInitialLoad: PropTypes.bool, + error: PropTypes.bool, + scope: PropTypes.string, + changeScope: PropTypes.func, + labelSeries: PropTypes.array, + dataSeries: PropTypes.array, + descriptions: PropTypes.array, + page: PropTypes.number, + isLastPage: PropTypes.bool, + changePage: PropTypes.func }; diff --git a/src/js/components/agency/visualizations/recipient/ScopeList.jsx b/src/js/components/agency/visualizations/recipient/ScopeList.jsx index 9192a8d698..a9f52b9c29 100644 --- a/src/js/components/agency/visualizations/recipient/ScopeList.jsx +++ b/src/js/components/agency/visualizations/recipient/ScopeList.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; @@ -11,8 +12,8 @@ import RankVisualizationScopeButton from 'components/search/visualizations/rank/RankVisualizationScopeButton'; const propTypes = { - scope: React.PropTypes.string, - changeScope: React.PropTypes.func + scope: PropTypes.string, + changeScope: PropTypes.func }; export default class ScopeList extends React.Component { diff --git a/src/js/components/article/Breadcrumb.jsx b/src/js/components/article/Breadcrumb.jsx index b2f1473c7a..47cdca390f 100644 --- a/src/js/components/article/Breadcrumb.jsx +++ b/src/js/components/article/Breadcrumb.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - title: React.PropTypes.string + title: PropTypes.string }; export default class Breadcrumb extends React.Component { diff --git a/src/js/components/award/AgencyInfo.jsx b/src/js/components/award/AgencyInfo.jsx index c10e4adb15..77401dae80 100644 --- a/src/js/components/award/AgencyInfo.jsx +++ b/src/js/components/award/AgencyInfo.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import InfoSnippet from './InfoSnippet'; const propTypes = { - selectedAward: React.PropTypes.object, - awardTypes: React.PropTypes.array + selectedAward: PropTypes.object, + awardTypes: PropTypes.array }; const defaultProps = { diff --git a/src/js/components/award/Award.jsx b/src/js/components/award/Award.jsx index 0452ce4f59..cda422e13a 100644 --- a/src/js/components/award/Award.jsx +++ b/src/js/components/award/Award.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as MetaTagHelper from 'helpers/metaTagHelper'; @@ -14,9 +15,9 @@ import Error from '../sharedComponents/Error'; import AwardInfo from './AwardInfo'; const propTypes = { - award: React.PropTypes.object, - noAward: React.PropTypes.bool, - inFlight: React.PropTypes.bool + award: PropTypes.object, + noAward: PropTypes.bool, + inFlight: PropTypes.bool }; export default class Award extends React.Component { diff --git a/src/js/components/award/AwardAmounts.jsx b/src/js/components/award/AwardAmounts.jsx index f42c11c576..18c7135cfe 100644 --- a/src/js/components/award/AwardAmounts.jsx +++ b/src/js/components/award/AwardAmounts.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import accounting from 'accounting'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -12,9 +13,9 @@ import AmountsChart from './visualizations/AmountsChart'; import LoanAmounts from './LoanAmounts'; const propTypes = { - selectedAward: React.PropTypes.object, - showPotential: React.PropTypes.bool, - typeString: React.PropTypes.string + selectedAward: PropTypes.object, + showPotential: PropTypes.bool, + typeString: PropTypes.string }; export default class AwardAmounts extends React.Component { diff --git a/src/js/components/award/AwardInfo.jsx b/src/js/components/award/AwardInfo.jsx index 02545f0073..c153019a8f 100644 --- a/src/js/components/award/AwardInfo.jsx +++ b/src/js/components/award/AwardInfo.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import $ from 'jquery'; @@ -14,7 +15,7 @@ import AwardFinancialAssistance from './financialAssistance/AwardFinancialAssist import DetailsSection from './details/DetailsSection'; const propTypes = { - selectedAward: React.PropTypes.object + selectedAward: PropTypes.object }; export default class AwardInfo extends React.Component { diff --git a/src/js/components/award/AwardInfoBar.jsx b/src/js/components/award/AwardInfoBar.jsx index d5d5106c85..5cd0c13049 100644 --- a/src/js/components/award/AwardInfoBar.jsx +++ b/src/js/components/award/AwardInfoBar.jsx @@ -4,11 +4,12 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import AgencyInfo from './AgencyInfo'; import RecipientInfo from './RecipientInfo'; const propTypes = { - selectedAward: React.PropTypes.object + selectedAward: PropTypes.object }; export default class AwardInfoBar extends React.Component { diff --git a/src/js/components/award/DetailRow.jsx b/src/js/components/award/DetailRow.jsx index a71896b44c..25177f79cd 100644 --- a/src/js/components/award/DetailRow.jsx +++ b/src/js/components/award/DetailRow.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - title: React.PropTypes.string, - value: React.PropTypes.string, - overflow: React.PropTypes.bool, - maxChars: React.PropTypes.number + title: PropTypes.string, + value: PropTypes.string, + overflow: PropTypes.bool, + maxChars: PropTypes.number }; export default class DetailRow extends React.Component { diff --git a/src/js/components/award/InfoSnippet.jsx b/src/js/components/award/InfoSnippet.jsx index decfe6f4bf..adf2415457 100644 --- a/src/js/components/award/InfoSnippet.jsx +++ b/src/js/components/award/InfoSnippet.jsx @@ -4,10 +4,11 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - label: React.PropTypes.string, - value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]) + label: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) }; export default class InfoSnippet extends React.Component { diff --git a/src/js/components/award/LoanAmounts.jsx b/src/js/components/award/LoanAmounts.jsx index 2a5ee57f85..bc1d361e13 100644 --- a/src/js/components/award/LoanAmounts.jsx +++ b/src/js/components/award/LoanAmounts.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - faceValue: React.PropTypes.string, - subsidy: React.PropTypes.string + faceValue: PropTypes.string, + subsidy: PropTypes.string }; export default class LoanAmounts extends React.Component { diff --git a/src/js/components/award/RecipientAddress.jsx b/src/js/components/award/RecipientAddress.jsx index 8e1534ed15..13aa0fca75 100644 --- a/src/js/components/award/RecipientAddress.jsx +++ b/src/js/components/award/RecipientAddress.jsx @@ -4,10 +4,11 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - recipient: React.PropTypes.object, - type: React.PropTypes.string + recipient: PropTypes.object, + type: PropTypes.string }; export default class RecipientAddress extends React.Component { diff --git a/src/js/components/award/RecipientInfo.jsx b/src/js/components/award/RecipientInfo.jsx index a9ab0402e3..d5a6033e1f 100644 --- a/src/js/components/award/RecipientInfo.jsx +++ b/src/js/components/award/RecipientInfo.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { toLower, includes } from 'lodash'; import { awardTypeGroups } from 'dataMapping/search/awardType'; import InfoSnippet from './InfoSnippet'; @@ -11,7 +12,7 @@ import RecipientAddress from './RecipientAddress'; const propTypes = { - recipient: React.PropTypes.object + recipient: PropTypes.object }; export default class RecipientInfo extends React.Component { diff --git a/src/js/components/award/SummaryBar.jsx b/src/js/components/award/SummaryBar.jsx index cda8ad0679..d40106eb65 100644 --- a/src/js/components/award/SummaryBar.jsx +++ b/src/js/components/award/SummaryBar.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import moment from 'moment'; import { startCase, toLower, includes } from 'lodash'; import * as SummaryPageHelper from 'helpers/summaryPageHelper'; @@ -13,7 +14,7 @@ import InfoSnippet from './InfoSnippet'; import MoreHeaderOptions from './MoreHeaderOptions'; const propTypes = { - selectedAward: React.PropTypes.object + selectedAward: PropTypes.object }; export default class SummaryBar extends React.Component { diff --git a/src/js/components/award/contract/AwardContract.jsx b/src/js/components/award/contract/AwardContract.jsx index 548c63fd6e..d80d65f375 100644 --- a/src/js/components/award/contract/AwardContract.jsx +++ b/src/js/components/award/contract/AwardContract.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as SummaryPageHelper from 'helpers/summaryPageHelper'; import AwardAmounts from '../AwardAmounts'; import ContractDetails from './ContractDetails'; const propTypes = { - selectedAward: React.PropTypes.object, - seeAdditional: React.PropTypes.func + selectedAward: PropTypes.object, + seeAdditional: PropTypes.func }; export default class AwardContract extends React.Component { diff --git a/src/js/components/award/contract/ContractDetails.jsx b/src/js/components/award/contract/ContractDetails.jsx index add721274e..7b0f9f802d 100644 --- a/src/js/components/award/contract/ContractDetails.jsx +++ b/src/js/components/award/contract/ContractDetails.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import moment from 'moment'; import DetailRow from '../DetailRow'; const propTypes = { - selectedAward: React.PropTypes.object, - seeAdditional: React.PropTypes.func, - maxChars: React.PropTypes.number + selectedAward: PropTypes.object, + seeAdditional: PropTypes.func, + maxChars: PropTypes.number }; export default class ContractDetails extends React.Component { diff --git a/src/js/components/award/details/DetailsSection.jsx b/src/js/components/award/details/DetailsSection.jsx index 1e867aac42..38e29dba17 100644 --- a/src/js/components/award/details/DetailsSection.jsx +++ b/src/js/components/award/details/DetailsSection.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import ContractTransactionsTableContainer from 'containers/award/table/ContractTransactionsTableContainer'; @@ -20,9 +21,9 @@ import AssistanceAdditionalDetails from './additional/AssistanceAdditionalDetail import ResultsTablePicker from '../../search/table/ResultsTablePicker'; const propTypes = { - award: React.PropTypes.object, - activeTab: React.PropTypes.string, - clickTab: React.PropTypes.func + award: PropTypes.object, + activeTab: PropTypes.string, + clickTab: PropTypes.func }; const tabs = [ diff --git a/src/js/components/award/details/DetailsTabBar.jsx b/src/js/components/award/details/DetailsTabBar.jsx index 61d1088254..31f62d3149 100644 --- a/src/js/components/award/details/DetailsTabBar.jsx +++ b/src/js/components/award/details/DetailsTabBar.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import DetailsTabItem from './DetailsTabItem'; const propTypes = { - activeTab: React.PropTypes.string, - clickTab: React.PropTypes.func, - tabOptions: React.PropTypes.array + activeTab: PropTypes.string, + clickTab: PropTypes.func, + tabOptions: PropTypes.array }; export default class DetailsTabBar extends React.Component { diff --git a/src/js/components/award/details/DetailsTabItem.jsx b/src/js/components/award/details/DetailsTabItem.jsx index 0e7600b32c..c97aeb7b9a 100644 --- a/src/js/components/award/details/DetailsTabItem.jsx +++ b/src/js/components/award/details/DetailsTabItem.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; const propTypes = { - label: React.PropTypes.string, - internal: React.PropTypes.string, - active: React.PropTypes.bool, - enabled: React.PropTypes.bool, - clickTab: React.PropTypes.func + label: PropTypes.string, + internal: PropTypes.string, + active: PropTypes.bool, + enabled: PropTypes.bool, + clickTab: PropTypes.func }; export default class DetailsTabItem extends React.Component { diff --git a/src/js/components/award/details/additional/AdditionalGroup.jsx b/src/js/components/award/details/additional/AdditionalGroup.jsx index 35445bbe63..d5c6d576e4 100644 --- a/src/js/components/award/details/additional/AdditionalGroup.jsx +++ b/src/js/components/award/details/additional/AdditionalGroup.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import AdditionalRow from './AdditionalRow'; const propTypes = { - fields: React.PropTypes.array, - data: React.PropTypes.object, - title: React.PropTypes.string + fields: PropTypes.array, + data: PropTypes.object, + title: PropTypes.string }; export default class AdditionalGroup extends React.Component { diff --git a/src/js/components/award/details/additional/AdditionalRow.jsx b/src/js/components/award/details/additional/AdditionalRow.jsx index c9e325c394..e6d532356f 100644 --- a/src/js/components/award/details/additional/AdditionalRow.jsx +++ b/src/js/components/award/details/additional/AdditionalRow.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - title: React.PropTypes.string, - value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]) + title: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) }; export default class AdditionalRow extends React.Component { diff --git a/src/js/components/award/details/additional/AssistanceAdditionalDetails.jsx b/src/js/components/award/details/additional/AssistanceAdditionalDetails.jsx index 2316f4e664..2b7e2c812d 100644 --- a/src/js/components/award/details/additional/AssistanceAdditionalDetails.jsx +++ b/src/js/components/award/details/additional/AssistanceAdditionalDetails.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isCancel } from 'axios'; import * as SearchHelper from 'helpers/searchHelper'; @@ -13,7 +14,7 @@ import FinancialSystemItem from 'models/results/other/FinancialSystemItem'; import AdditionalGroup from './AdditionalGroup'; const propTypes = { - award: React.PropTypes.object + award: PropTypes.object }; export default class AssistanceAdditionalDetails extends React.Component { diff --git a/src/js/components/award/details/additional/ContractAdditionalDetails.jsx b/src/js/components/award/details/additional/ContractAdditionalDetails.jsx index 8a9efb4a3f..5914223847 100644 --- a/src/js/components/award/details/additional/ContractAdditionalDetails.jsx +++ b/src/js/components/award/details/additional/ContractAdditionalDetails.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as DataFields from 'dataMapping/contracts/additionalDetails'; import AdditionalGroup from './AdditionalGroup'; const propTypes = { - award: React.PropTypes.object + award: PropTypes.object }; export default class ContractAdditionalDetails extends React.Component { diff --git a/src/js/components/award/financialAssistance/AwardFinancialAssistance.jsx b/src/js/components/award/financialAssistance/AwardFinancialAssistance.jsx index 4801015f0e..912722d663 100644 --- a/src/js/components/award/financialAssistance/AwardFinancialAssistance.jsx +++ b/src/js/components/award/financialAssistance/AwardFinancialAssistance.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as SummaryPageHelper from 'helpers/summaryPageHelper'; import AwardAmounts from '../AwardAmounts'; import FinancialAssistanceDetails from './FinancialAssistanceDetails'; const propTypes = { - selectedAward: React.PropTypes.object, - seeAdditional: React.PropTypes.func + selectedAward: PropTypes.object, + seeAdditional: PropTypes.func }; export default class AwardFinancialAssistance extends React.Component { diff --git a/src/js/components/award/financialAssistance/FinancialAssistanceDetails.jsx b/src/js/components/award/financialAssistance/FinancialAssistanceDetails.jsx index 3bfd9faf4d..893bd7e714 100644 --- a/src/js/components/award/financialAssistance/FinancialAssistanceDetails.jsx +++ b/src/js/components/award/financialAssistance/FinancialAssistanceDetails.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import moment from 'moment'; import { capitalize } from 'lodash'; import * as SummaryPageHelper from 'helpers/summaryPageHelper'; import DetailRow from '../DetailRow'; const propTypes = { - selectedAward: React.PropTypes.object, - seeAdditional: React.PropTypes.func + selectedAward: PropTypes.object, + seeAdditional: PropTypes.func }; export default class FinancialAssistanceDetails extends React.Component { diff --git a/src/js/components/award/subawards/SubawardsTable.jsx b/src/js/components/award/subawards/SubawardsTable.jsx index da64e18dee..085de1807f 100644 --- a/src/js/components/award/subawards/SubawardsTable.jsx +++ b/src/js/components/award/subawards/SubawardsTable.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { measureTableHeader } from 'helpers/textMeasurement'; @@ -24,12 +25,12 @@ const rowHeight = 40; const tableHeight = 12.5 * rowHeight; const propTypes = { - inFlight: React.PropTypes.bool, - tableWidth: React.PropTypes.number, - award: React.PropTypes.object, - subawards: React.PropTypes.array, - meta: React.PropTypes.object, - loadNextPage: React.PropTypes.func + inFlight: PropTypes.bool, + tableWidth: PropTypes.number, + award: PropTypes.object, + subawards: PropTypes.array, + meta: PropTypes.object, + loadNextPage: PropTypes.func }; export default class SubawardsTable extends React.Component { diff --git a/src/js/components/award/subawards/cells/SubawardsHeaderCell.jsx b/src/js/components/award/subawards/cells/SubawardsHeaderCell.jsx index 33699c7c53..2f7c69f397 100644 --- a/src/js/components/award/subawards/cells/SubawardsHeaderCell.jsx +++ b/src/js/components/award/subawards/cells/SubawardsHeaderCell.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import tableMapping from 'dataMapping/contracts/subawardTable'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - setSubawardSort: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + setSubawardSort: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class SubawardsHeaderCell extends React.Component { diff --git a/src/js/components/award/table/AssistanceTransactionsTable.jsx b/src/js/components/award/table/AssistanceTransactionsTable.jsx index 9fd76465a7..595365c6af 100644 --- a/src/js/components/award/table/AssistanceTransactionsTable.jsx +++ b/src/js/components/award/table/AssistanceTransactionsTable.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { measureTableHeader } from 'helpers/textMeasurement'; @@ -21,10 +22,10 @@ const rowHeight = 40; const tableHeight = 12.5 * rowHeight; const propTypes = { - award: React.PropTypes.object, - tableWidth: React.PropTypes.number, - inFlight: React.PropTypes.bool, - nextTransactionPage: React.PropTypes.func + award: PropTypes.object, + tableWidth: PropTypes.number, + inFlight: PropTypes.bool, + nextTransactionPage: PropTypes.func }; export default class AssistanceTransactionsTable extends React.Component { diff --git a/src/js/components/award/table/ContractTransactionsTable.jsx b/src/js/components/award/table/ContractTransactionsTable.jsx index 6d4e284720..a35aa386c3 100644 --- a/src/js/components/award/table/ContractTransactionsTable.jsx +++ b/src/js/components/award/table/ContractTransactionsTable.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import tableMapping from 'dataMapping/contracts/transactionTable'; @@ -21,10 +22,10 @@ const rowHeight = 40; const tableHeight = 12.5 * rowHeight; const propTypes = { - award: React.PropTypes.object, - tableWidth: React.PropTypes.number, - inFlight: React.PropTypes.bool, - nextTransactionPage: React.PropTypes.func + award: PropTypes.object, + tableWidth: PropTypes.number, + inFlight: PropTypes.bool, + nextTransactionPage: PropTypes.func }; export default class ContractTransactionsTable extends React.Component { diff --git a/src/js/components/award/table/FinancialSystemTable.jsx b/src/js/components/award/table/FinancialSystemTable.jsx index 89947bee16..f55d614f97 100644 --- a/src/js/components/award/table/FinancialSystemTable.jsx +++ b/src/js/components/award/table/FinancialSystemTable.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import IBTable from 'components/sharedComponents/IBTable/IBTable'; @@ -21,10 +22,10 @@ const rowHeight = 40; const tableHeight = 12.5 * rowHeight; const propTypes = { - award: React.PropTypes.object, - tableWidth: React.PropTypes.number, - nextPage: React.PropTypes.func, - inFlight: React.PropTypes.bool + award: PropTypes.object, + tableWidth: PropTypes.number, + nextPage: PropTypes.func, + inFlight: PropTypes.bool }; export default class FinancialSystemTable extends React.Component { diff --git a/src/js/components/award/table/LoanTransactionsTable.jsx b/src/js/components/award/table/LoanTransactionsTable.jsx index cb46cd6e00..2f9e6d0ece 100644 --- a/src/js/components/award/table/LoanTransactionsTable.jsx +++ b/src/js/components/award/table/LoanTransactionsTable.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import tableMapping from 'dataMapping/financialAssistance/loanTransactionTable'; @@ -21,10 +22,10 @@ const rowHeight = 40; const tableHeight = 12.5 * rowHeight; const propTypes = { - award: React.PropTypes.object, - tableWidth: React.PropTypes.number, - inFlight: React.PropTypes.bool, - nextTransactionPage: React.PropTypes.func + award: PropTypes.object, + tableWidth: PropTypes.number, + inFlight: PropTypes.bool, + nextTransactionPage: PropTypes.func }; export default class LoanTransactionsTable extends React.Component { diff --git a/src/js/components/award/table/SummaryPageTableMessage.jsx b/src/js/components/award/table/SummaryPageTableMessage.jsx index 50d8caf705..d23ca0c7f3 100644 --- a/src/js/components/award/table/SummaryPageTableMessage.jsx +++ b/src/js/components/award/table/SummaryPageTableMessage.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - message: React.PropTypes.string + message: PropTypes.string }; export default class SummaryPageTableMessage extends React.Component { diff --git a/src/js/components/award/table/cells/AssistanceTransactionGenericCell.jsx b/src/js/components/award/table/cells/AssistanceTransactionGenericCell.jsx index cc92671ea6..afcf33c589 100644 --- a/src/js/components/award/table/cells/AssistanceTransactionGenericCell.jsx +++ b/src/js/components/award/table/cells/AssistanceTransactionGenericCell.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - data: React.PropTypes.string, - rowIndex: React.PropTypes.number, - column: React.PropTypes.string, - isLastColumn: React.PropTypes.bool + data: PropTypes.string, + rowIndex: PropTypes.number, + column: PropTypes.string, + isLastColumn: PropTypes.bool }; export default class AssistanceTransactionGenericCell extends React.Component { diff --git a/src/js/components/award/table/cells/AssistanceTransactionHeaderCell.jsx b/src/js/components/award/table/cells/AssistanceTransactionHeaderCell.jsx index c17e6b84fa..76fcb23e4c 100644 --- a/src/js/components/award/table/cells/AssistanceTransactionHeaderCell.jsx +++ b/src/js/components/award/table/cells/AssistanceTransactionHeaderCell.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import tableMapping from 'dataMapping/financialAssistance/financialAssistanceTransactionTable'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - setTransactionSort: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + setTransactionSort: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class AssistanceTransactionHeaderCell extends React.Component { diff --git a/src/js/components/award/table/cells/FinSysGenericCell.jsx b/src/js/components/award/table/cells/FinSysGenericCell.jsx index fb0d96e335..3781a93ea5 100644 --- a/src/js/components/award/table/cells/FinSysGenericCell.jsx +++ b/src/js/components/award/table/cells/FinSysGenericCell.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - data: React.PropTypes.string, - rowIndex: React.PropTypes.number, - column: React.PropTypes.string, - isLastColumn: React.PropTypes.bool + data: PropTypes.string, + rowIndex: PropTypes.number, + column: PropTypes.string, + isLastColumn: PropTypes.bool }; export default class FinSysGenericCell extends React.Component { diff --git a/src/js/components/award/table/cells/FinSysHeaderCell.jsx b/src/js/components/award/table/cells/FinSysHeaderCell.jsx index 29fdd68352..ffcc68c10d 100644 --- a/src/js/components/award/table/cells/FinSysHeaderCell.jsx +++ b/src/js/components/award/table/cells/FinSysHeaderCell.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import tableMapping from 'dataMapping/contracts/financialSystem'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - setFinSysSort: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + setFinSysSort: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class FinSysHeaderCell extends React.Component { diff --git a/src/js/components/award/table/cells/LoanTransactionHeaderCell.jsx b/src/js/components/award/table/cells/LoanTransactionHeaderCell.jsx index a54ad0d963..15ad4edd49 100644 --- a/src/js/components/award/table/cells/LoanTransactionHeaderCell.jsx +++ b/src/js/components/award/table/cells/LoanTransactionHeaderCell.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import tableMapping from 'dataMapping/financialAssistance/loanTransactionTable'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - setTransactionSort: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + setTransactionSort: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class LoanTransactionHeaderCell extends React.Component { diff --git a/src/js/components/award/table/cells/TransactionTableGenericCell.jsx b/src/js/components/award/table/cells/TransactionTableGenericCell.jsx index 1ab7b1611d..5d7c9ebaa9 100644 --- a/src/js/components/award/table/cells/TransactionTableGenericCell.jsx +++ b/src/js/components/award/table/cells/TransactionTableGenericCell.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - data: React.PropTypes.string, - rowIndex: React.PropTypes.number, - column: React.PropTypes.string, - isLastColumn: React.PropTypes.bool + data: PropTypes.string, + rowIndex: PropTypes.number, + column: PropTypes.string, + isLastColumn: PropTypes.bool }; export default class TransactionTableGenericCell extends React.Component { diff --git a/src/js/components/award/table/cells/TransactionTableHeaderCell.jsx b/src/js/components/award/table/cells/TransactionTableHeaderCell.jsx index dd5d49618e..22a3675d7e 100644 --- a/src/js/components/award/table/cells/TransactionTableHeaderCell.jsx +++ b/src/js/components/award/table/cells/TransactionTableHeaderCell.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import tableMapping from 'dataMapping/contracts/transactionTable'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - setTransactionSort: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + setTransactionSort: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class TransactionTableHeaderCell extends React.Component { diff --git a/src/js/components/award/visualizations/AmountsChart.jsx b/src/js/components/award/visualizations/AmountsChart.jsx index 5d9d1d9e83..5c97101bb9 100644 --- a/src/js/components/award/visualizations/AmountsChart.jsx +++ b/src/js/components/award/visualizations/AmountsChart.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { scaleLinear } from 'd3-scale'; import { capitalize } from 'lodash'; @@ -15,12 +16,12 @@ import IndividualBar from './IndividualBar'; import AwardLabels from './AwardLabels'; const propTypes = { - potential: React.PropTypes.number, - current: React.PropTypes.number, - graphHeight: React.PropTypes.number, - awardId: React.PropTypes.number, - showPotential: React.PropTypes.bool, - type: React.PropTypes.string + potential: PropTypes.number, + current: PropTypes.number, + graphHeight: PropTypes.number, + awardId: PropTypes.number, + showPotential: PropTypes.bool, + type: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/award/visualizations/AwardLabels.jsx b/src/js/components/award/visualizations/AwardLabels.jsx index 2b3e071230..8df5f1fe90 100644 --- a/src/js/components/award/visualizations/AwardLabels.jsx +++ b/src/js/components/award/visualizations/AwardLabels.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { capitalize } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -12,19 +13,19 @@ import AwardLabelsLine from './AwardLabelsLine'; import AwardLabelsPoly from './AwardLabelsPoly'; const propTypes = { - name: React.PropTypes.string, - amount: React.PropTypes.number, - subtitle: React.PropTypes.string, - line: React.PropTypes.string, - labelDistance: React.PropTypes.number, - groupTransform: React.PropTypes.string, - singleTransform: React.PropTypes.string, - labelPadding: React.PropTypes.number, - currentY: React.PropTypes.number, - graphHeight: React.PropTypes.number, - labelWidth: React.PropTypes.number, - currentMiddle: React.PropTypes.number, - type: React.PropTypes.string + name: PropTypes.string, + amount: PropTypes.number, + subtitle: PropTypes.string, + line: PropTypes.string, + labelDistance: PropTypes.number, + groupTransform: PropTypes.string, + singleTransform: PropTypes.string, + labelPadding: PropTypes.number, + currentY: PropTypes.number, + graphHeight: PropTypes.number, + labelWidth: PropTypes.number, + currentMiddle: PropTypes.number, + type: PropTypes.string }; export default class AwardLabels extends React.Component { diff --git a/src/js/components/award/visualizations/AwardLabelsLine.jsx b/src/js/components/award/visualizations/AwardLabelsLine.jsx index a9701e8398..e231f1d3fe 100644 --- a/src/js/components/award/visualizations/AwardLabelsLine.jsx +++ b/src/js/components/award/visualizations/AwardLabelsLine.jsx @@ -4,10 +4,10 @@ **/ import React from 'react'; - +import PropTypes from 'prop-types'; const propTypes = { - labelDistance: React.PropTypes.number + labelDistance: PropTypes.number }; export default class AwardLabelsLine extends React.Component { diff --git a/src/js/components/award/visualizations/AwardLabelsPoly.jsx b/src/js/components/award/visualizations/AwardLabelsPoly.jsx index c2e991a904..b5271d3bf0 100644 --- a/src/js/components/award/visualizations/AwardLabelsPoly.jsx +++ b/src/js/components/award/visualizations/AwardLabelsPoly.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - labelWidth: React.PropTypes.number, - labelPadding: React.PropTypes.number, - labelDistance: React.PropTypes.number, - currentY: React.PropTypes.number, - graphHeight: React.PropTypes.number, - currentMiddle: React.PropTypes.number + labelWidth: PropTypes.number, + labelPadding: PropTypes.number, + labelDistance: PropTypes.number, + currentY: PropTypes.number, + graphHeight: PropTypes.number, + currentMiddle: PropTypes.number }; export default class AwardLabelsPoly extends React.Component { diff --git a/src/js/components/award/visualizations/CurrentAwardBar.jsx b/src/js/components/award/visualizations/CurrentAwardBar.jsx index e99b0a097a..bfe1adbb50 100644 --- a/src/js/components/award/visualizations/CurrentAwardBar.jsx +++ b/src/js/components/award/visualizations/CurrentAwardBar.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - height: React.PropTypes.number, - data: React.PropTypes.string + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + height: PropTypes.number, + data: PropTypes.string }; export default class CurrentAwardBar extends React.Component { diff --git a/src/js/components/award/visualizations/IndividualBar.jsx b/src/js/components/award/visualizations/IndividualBar.jsx index 2c6416ad08..6c48e5db1c 100644 --- a/src/js/components/award/visualizations/IndividualBar.jsx +++ b/src/js/components/award/visualizations/IndividualBar.jsx @@ -4,11 +4,12 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - name: React.PropTypes.string, - yValue: React.PropTypes.number, - barValue: React.PropTypes.object + name: PropTypes.string, + yValue: PropTypes.number, + barValue: PropTypes.object }; export default class IndividualBar extends React.Component { diff --git a/src/js/components/award/visualizations/PotentialAwardBar.jsx b/src/js/components/award/visualizations/PotentialAwardBar.jsx index e2ab795530..c0b0be7b9f 100644 --- a/src/js/components/award/visualizations/PotentialAwardBar.jsx +++ b/src/js/components/award/visualizations/PotentialAwardBar.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - height: React.PropTypes.number, - dataY: React.PropTypes.number + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + height: PropTypes.number, + dataY: PropTypes.number }; export default class PotentialAwardBar extends React.Component { diff --git a/src/js/components/award/visualizations/SubAwardBar.jsx b/src/js/components/award/visualizations/SubAwardBar.jsx index fe59c31f9a..4788ba0b96 100644 --- a/src/js/components/award/visualizations/SubAwardBar.jsx +++ b/src/js/components/award/visualizations/SubAwardBar.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - x: React.PropTypes.string, - y: React.PropTypes.number, - width: React.PropTypes.number, - height: React.PropTypes.number, - dataY: React.PropTypes.number + x: PropTypes.string, + y: PropTypes.number, + width: PropTypes.number, + height: PropTypes.number, + dataY: PropTypes.number }; export default class SubAwardBar extends React.Component { diff --git a/src/js/components/glossary/AnimatedGlossaryWrapper.jsx b/src/js/components/glossary/AnimatedGlossaryWrapper.jsx index e065a62165..d67e2841ef 100644 --- a/src/js/components/glossary/AnimatedGlossaryWrapper.jsx +++ b/src/js/components/glossary/AnimatedGlossaryWrapper.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup'; import Glossary from './Glossary'; const propTypes = { - glossary: React.PropTypes.object + glossary: PropTypes.object }; export default class AnimatedGlossaryWrapper extends React.Component { diff --git a/src/js/components/glossary/Glossary.jsx b/src/js/components/glossary/Glossary.jsx index 2218801fd8..e2ffa555e6 100644 --- a/src/js/components/glossary/Glossary.jsx +++ b/src/js/components/glossary/Glossary.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Scrollbars } from 'react-custom-scrollbars'; import Mousetrap from 'mousetrap'; @@ -13,10 +14,10 @@ import GlossaryDefinition from './definition/GlossaryDefinition'; import NoResults from './noResults/NoResults'; const propTypes = { - glossary: React.PropTypes.object, - loading: React.PropTypes.bool, - error: React.PropTypes.bool, - hideGlossary: React.PropTypes.func + glossary: PropTypes.object, + loading: PropTypes.bool, + error: PropTypes.bool, + hideGlossary: PropTypes.func }; export default class Glossary extends React.Component { diff --git a/src/js/components/glossary/GlossaryHeader.jsx b/src/js/components/glossary/GlossaryHeader.jsx index f799089b17..b968f3ac1a 100644 --- a/src/js/components/glossary/GlossaryHeader.jsx +++ b/src/js/components/glossary/GlossaryHeader.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import GlossarySearchBar from './GlossarySearchBar'; const propTypes = { - hideGlossary: React.PropTypes.func + hideGlossary: PropTypes.func }; export default class GlossaryHeader extends React.Component { diff --git a/src/js/components/glossary/GlossarySearchBar.jsx b/src/js/components/glossary/GlossarySearchBar.jsx index 2624bcb85e..9995088688 100644 --- a/src/js/components/glossary/GlossarySearchBar.jsx +++ b/src/js/components/glossary/GlossarySearchBar.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Search } from 'components/sharedComponents/icons/Icons'; const propTypes = { - glossary: React.PropTypes.object, - setSearchValue: React.PropTypes.func, - performSearch: React.PropTypes.func + glossary: PropTypes.object, + setSearchValue: PropTypes.func, + performSearch: PropTypes.func }; export default class GlossarySearchBar extends React.Component { diff --git a/src/js/components/glossary/definition/DefinitionTabs.jsx b/src/js/components/glossary/definition/DefinitionTabs.jsx index bf1ac6b48f..43cbd2b26e 100644 --- a/src/js/components/glossary/definition/DefinitionTabs.jsx +++ b/src/js/components/glossary/definition/DefinitionTabs.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import TabItem from './TabItem'; const propTypes = { - activeTab: React.PropTypes.string, - clickedTab: React.PropTypes.func, - hasPlain: React.PropTypes.bool, - hasOfficial: React.PropTypes.bool + activeTab: PropTypes.string, + clickedTab: PropTypes.func, + hasPlain: PropTypes.bool, + hasOfficial: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/glossary/definition/GlossaryDefinition.jsx b/src/js/components/glossary/definition/GlossaryDefinition.jsx index 00a7b026f2..4de9fb6d9e 100644 --- a/src/js/components/glossary/definition/GlossaryDefinition.jsx +++ b/src/js/components/glossary/definition/GlossaryDefinition.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { AngleLeft } from 'components/sharedComponents/icons/Icons'; @@ -11,8 +12,8 @@ import DefinitionTabs from './DefinitionTabs'; import ItemDefinition from './ItemDefinition'; const propTypes = { - glossary: React.PropTypes.object, - clearGlossaryTerm: React.PropTypes.func + glossary: PropTypes.object, + clearGlossaryTerm: PropTypes.func }; export default class GlossaryDefinition extends React.Component { diff --git a/src/js/components/glossary/definition/ItemDefinition.jsx b/src/js/components/glossary/definition/ItemDefinition.jsx index 4dd4500284..1c0f75c101 100644 --- a/src/js/components/glossary/definition/ItemDefinition.jsx +++ b/src/js/components/glossary/definition/ItemDefinition.jsx @@ -4,16 +4,17 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ReactMarkdown from 'react-markdown'; import MoreResources from './MoreResources'; import SmartLink from './SmartLink'; const propTypes = { - type: React.PropTypes.string, - term: React.PropTypes.string, - data_act_term: React.PropTypes.string, - resources: React.PropTypes.string + type: PropTypes.string, + term: PropTypes.string, + data_act_term: PropTypes.string, + resources: PropTypes.string }; export default class ItemDefinition extends React.Component { diff --git a/src/js/components/glossary/definition/MoreResources.jsx b/src/js/components/glossary/definition/MoreResources.jsx index 98fe3ec948..591ef51975 100644 --- a/src/js/components/glossary/definition/MoreResources.jsx +++ b/src/js/components/glossary/definition/MoreResources.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ReactMarkdown from 'react-markdown'; import SmartLink from './SmartLink'; const propTypes = { - resources: React.PropTypes.string + resources: PropTypes.string }; export default class MoreResources extends React.Component { diff --git a/src/js/components/glossary/definition/SmartLink.jsx b/src/js/components/glossary/definition/SmartLink.jsx index 31c84554ac..14e89eab05 100644 --- a/src/js/components/glossary/definition/SmartLink.jsx +++ b/src/js/components/glossary/definition/SmartLink.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Router from 'containers/router/Router'; const propTypes = { - href: React.PropTypes.string, - children: React.PropTypes.node + href: PropTypes.string, + children: PropTypes.node }; export default class SmartLink extends React.Component { diff --git a/src/js/components/glossary/definition/TabItem.jsx b/src/js/components/glossary/definition/TabItem.jsx index 66a7e483e9..037b42b58a 100644 --- a/src/js/components/glossary/definition/TabItem.jsx +++ b/src/js/components/glossary/definition/TabItem.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - active: React.PropTypes.bool, - label: React.PropTypes.string, - type: React.PropTypes.string, - clickedTab: React.PropTypes.func + active: PropTypes.bool, + label: PropTypes.string, + type: PropTypes.string, + clickedTab: PropTypes.func }; export default class TabItem extends React.Component { diff --git a/src/js/components/glossary/noResults/NoResults.jsx b/src/js/components/glossary/noResults/NoResults.jsx index b5570df8f1..ebebd1a902 100644 --- a/src/js/components/glossary/noResults/NoResults.jsx +++ b/src/js/components/glossary/noResults/NoResults.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - glossary: React.PropTypes.object, - searchLoading: React.PropTypes.bool + glossary: PropTypes.object, + searchLoading: PropTypes.bool }; export default class NoResults extends React.Component { diff --git a/src/js/components/glossary/search/GlossarySearchResults.jsx b/src/js/components/glossary/search/GlossarySearchResults.jsx index 7cb982e771..b9c850affb 100644 --- a/src/js/components/glossary/search/GlossarySearchResults.jsx +++ b/src/js/components/glossary/search/GlossarySearchResults.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { concat, sortBy } from 'lodash'; import ResultGroup from './ResultGroup'; const propTypes = { - glossary: React.PropTypes.object, - searchLoading: React.PropTypes.bool, - setGlossaryTerm: React.PropTypes.func + glossary: PropTypes.object, + searchLoading: PropTypes.bool, + setGlossaryTerm: PropTypes.func }; export default class GlossarySearchResults extends React.Component { diff --git a/src/js/components/glossary/search/ResultGroup.jsx b/src/js/components/glossary/search/ResultGroup.jsx index 933cfd21fd..19bd4e6646 100644 --- a/src/js/components/glossary/search/ResultGroup.jsx +++ b/src/js/components/glossary/search/ResultGroup.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ResultItem from './ResultItem'; const propTypes = { - title: React.PropTypes.string, - items: React.PropTypes.array, - search: React.PropTypes.string, - selectTerm: React.PropTypes.func + title: PropTypes.string, + items: PropTypes.array, + search: PropTypes.string, + selectTerm: PropTypes.func }; export default class ResultGroup extends React.Component { diff --git a/src/js/components/glossary/search/ResultItem.jsx b/src/js/components/glossary/search/ResultItem.jsx index 6acc0b38c8..ecfb09458a 100644 --- a/src/js/components/glossary/search/ResultItem.jsx +++ b/src/js/components/glossary/search/ResultItem.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - item: React.PropTypes.object, - search: React.PropTypes.string, - selectTerm: React.PropTypes.func + item: PropTypes.object, + search: PropTypes.string, + selectTerm: PropTypes.func }; export default class ResultItem extends React.Component { diff --git a/src/js/components/homepage/CategorySection.jsx b/src/js/components/homepage/CategorySection.jsx index 6db1c5121c..11ee886bd3 100644 --- a/src/js/components/homepage/CategorySection.jsx +++ b/src/js/components/homepage/CategorySection.jsx @@ -4,14 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; - import CategoryMap from './visualizations/categoryMap/CategoryMap'; const propTypes = { - breakdown: React.PropTypes.object, - colors: React.PropTypes.array + breakdown: PropTypes.object, + colors: PropTypes.array }; export default class CategorySection extends React.Component { diff --git a/src/js/components/homepage/LinksSectionBox.jsx b/src/js/components/homepage/LinksSectionBox.jsx index 88638835c1..1d7a87d577 100644 --- a/src/js/components/homepage/LinksSectionBox.jsx +++ b/src/js/components/homepage/LinksSectionBox.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as HomeIcons from 'components/sharedComponents/icons/home/HomeIcons'; const propTypes = { - icon: React.PropTypes.string, - title: React.PropTypes.string, - subtitle: React.PropTypes.string, - linkText: React.PropTypes.string, - linkUrl: React.PropTypes.string + icon: PropTypes.string, + title: PropTypes.string, + subtitle: PropTypes.string, + linkText: PropTypes.string, + linkUrl: PropTypes.string }; export default class LinksSectionBox extends React.Component { diff --git a/src/js/components/homepage/visualizations/categoryMap/BudgetLabel.jsx b/src/js/components/homepage/visualizations/categoryMap/BudgetLabel.jsx index 7f5e6edac0..28e0245c7a 100644 --- a/src/js/components/homepage/visualizations/categoryMap/BudgetLabel.jsx +++ b/src/js/components/homepage/visualizations/categoryMap/BudgetLabel.jsx @@ -4,16 +4,17 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - labelWidth: React.PropTypes.number, - labelPadding: React.PropTypes.number, - labelDistance: React.PropTypes.number, - currentY: React.PropTypes.number, - currentX: React.PropTypes.number, - graphHeight: React.PropTypes.number, - graphWidth: React.PropTypes.number, - size: React.PropTypes.string + labelWidth: PropTypes.number, + labelPadding: PropTypes.number, + labelDistance: PropTypes.number, + currentY: PropTypes.number, + currentX: PropTypes.number, + graphHeight: PropTypes.number, + graphWidth: PropTypes.number, + size: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/homepage/visualizations/categoryMap/BudgetLine.jsx b/src/js/components/homepage/visualizations/categoryMap/BudgetLine.jsx index 4ba5b8bc3d..14adf38ee6 100644 --- a/src/js/components/homepage/visualizations/categoryMap/BudgetLine.jsx +++ b/src/js/components/homepage/visualizations/categoryMap/BudgetLine.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import BudgetLabel from './BudgetLabel'; const propTypes = { - size: React.PropTypes.string, - gTransform: React.PropTypes.string, - rectTransform: React.PropTypes.string, - textTransform: React.PropTypes.string, - label: React.PropTypes.string + size: PropTypes.string, + gTransform: PropTypes.string, + rectTransform: PropTypes.string, + textTransform: PropTypes.string, + label: PropTypes.string }; export default class BudgetLine extends React.Component { diff --git a/src/js/components/homepage/visualizations/categoryMap/CategoryMap.jsx b/src/js/components/homepage/visualizations/categoryMap/CategoryMap.jsx index b6c71b3a4f..5a0e894b8e 100644 --- a/src/js/components/homepage/visualizations/categoryMap/CategoryMap.jsx +++ b/src/js/components/homepage/visualizations/categoryMap/CategoryMap.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { hierarchy, treemap, treemapDice, treemapSlice } from 'd3-hierarchy'; import { throttle, find } from 'lodash'; import { HandDrawnArrow } from 'components/sharedComponents/icons/Icons'; @@ -13,9 +14,9 @@ import CategoryMapTooltip from './CategoryMapTooltip'; import BudgetLine from './BudgetLine'; const propTypes = { - breakdown: React.PropTypes.object, - colors: React.PropTypes.array, - tooltipStyles: React.PropTypes.object + breakdown: PropTypes.object, + colors: PropTypes.array, + tooltipStyles: PropTypes.object }; export default class CategoryMap extends React.Component { diff --git a/src/js/components/homepage/visualizations/categoryMap/CategoryMapCell.jsx b/src/js/components/homepage/visualizations/categoryMap/CategoryMapCell.jsx index e3fab087c7..258aee753a 100644 --- a/src/js/components/homepage/visualizations/categoryMap/CategoryMapCell.jsx +++ b/src/js/components/homepage/visualizations/categoryMap/CategoryMapCell.jsx @@ -4,20 +4,21 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { truncate } from 'lodash'; const propTypes = { - label: React.PropTypes.string, - value: React.PropTypes.number, - x0: React.PropTypes.number, - x1: React.PropTypes.number, - y0: React.PropTypes.number, - y1: React.PropTypes.number, - categoryID: React.PropTypes.number, - color: React.PropTypes.string, - tooltipStyles: React.PropTypes.object, - toggleTooltipIn: React.PropTypes.func, - toggleTooltipOut: React.PropTypes.func + label: PropTypes.string, + value: PropTypes.number, + x0: PropTypes.number, + x1: PropTypes.number, + y0: PropTypes.number, + y1: PropTypes.number, + categoryID: PropTypes.number, + color: PropTypes.string, + tooltipStyles: PropTypes.object, + toggleTooltipIn: PropTypes.func, + toggleTooltipOut: PropTypes.func }; export default class CategoryMapCell extends React.Component { diff --git a/src/js/components/homepage/visualizations/categoryMap/CategoryMapTooltip.jsx b/src/js/components/homepage/visualizations/categoryMap/CategoryMapTooltip.jsx index 416266ee1d..fad8d2447f 100644 --- a/src/js/components/homepage/visualizations/categoryMap/CategoryMapTooltip.jsx +++ b/src/js/components/homepage/visualizations/categoryMap/CategoryMapTooltip.jsx @@ -4,16 +4,17 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - name: React.PropTypes.string, - dollar: React.PropTypes.number, - description: React.PropTypes.string, - height: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number + name: PropTypes.string, + dollar: PropTypes.number, + description: PropTypes.string, + height: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number }; export default class CategoryMapTooltip extends React.Component { diff --git a/src/js/components/homepage/visualizations/geo/MapList.jsx b/src/js/components/homepage/visualizations/geo/MapList.jsx index a9bd483789..715c2570b5 100644 --- a/src/js/components/homepage/visualizations/geo/MapList.jsx +++ b/src/js/components/homepage/visualizations/geo/MapList.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { orderBy, uniqueId } from 'lodash'; import IBTable from 'components/sharedComponents/IBTable/IBTable'; @@ -16,8 +17,8 @@ import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableG import MapListHeaderCell from './cells/MapListHeaderCell'; const propTypes = { - loading: React.PropTypes.bool, - data: React.PropTypes.array + loading: PropTypes.bool, + data: PropTypes.array }; const rowHeight = 40; diff --git a/src/js/components/homepage/visualizations/geo/MapToggleList.jsx b/src/js/components/homepage/visualizations/geo/MapToggleList.jsx index 50df64aaf0..5c355751e4 100644 --- a/src/js/components/homepage/visualizations/geo/MapToggleList.jsx +++ b/src/js/components/homepage/visualizations/geo/MapToggleList.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import RankVisualizationScopeButton from 'components/search/visualizations/rank/RankVisualizationScopeButton'; const propTypes = { - view: React.PropTypes.string, - changeView: React.PropTypes.func + view: PropTypes.string, + changeView: PropTypes.func }; export default class MapToggleList extends React.Component { diff --git a/src/js/components/homepage/visualizations/geo/MapVisualization.jsx b/src/js/components/homepage/visualizations/geo/MapVisualization.jsx index 19f8d38eaa..0d142d976d 100644 --- a/src/js/components/homepage/visualizations/geo/MapVisualization.jsx +++ b/src/js/components/homepage/visualizations/geo/MapVisualization.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { indexOf } from 'lodash'; import ToggleButton from 'components/sharedComponents/ToggleButton'; @@ -14,9 +15,9 @@ import GeoCapitaTooltip from './tooltips/GeoCapitaTooltip'; import HomepageMapCitation from './HomepageMapCitation'; const propTypes = { - data: React.PropTypes.object, - showPerCapita: React.PropTypes.bool, - togglePerCapita: React.PropTypes.func + data: PropTypes.object, + showPerCapita: PropTypes.bool, + togglePerCapita: PropTypes.func }; export default class MapVisualization extends React.Component { diff --git a/src/js/components/homepage/visualizations/geo/MapVisualizationWrapper.jsx b/src/js/components/homepage/visualizations/geo/MapVisualizationWrapper.jsx index 6fcf560d1b..ff9812a4ab 100644 --- a/src/js/components/homepage/visualizations/geo/MapVisualizationWrapper.jsx +++ b/src/js/components/homepage/visualizations/geo/MapVisualizationWrapper.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { uniqueId, isEqual } from 'lodash'; import MapVisualization from './MapVisualization'; @@ -12,7 +13,7 @@ import MapToggleList from './MapToggleList'; import HomepageMapCitation from './HomepageMapCitation'; const propTypes = { - data: React.PropTypes.object + data: PropTypes.object }; export default class MapVisualizationWrapper extends React.Component { diff --git a/src/js/components/homepage/visualizations/geo/cells/MapListHeaderCell.jsx b/src/js/components/homepage/visualizations/geo/cells/MapListHeaderCell.jsx index 90fc89c20e..019b058aec 100644 --- a/src/js/components/homepage/visualizations/geo/cells/MapListHeaderCell.jsx +++ b/src/js/components/homepage/visualizations/geo/cells/MapListHeaderCell.jsx @@ -4,16 +4,17 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - changeSearchOrder: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + changeSearchOrder: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class MapListHeaderCell extends React.Component { diff --git a/src/js/components/homepage/visualizations/geo/tooltips/GeoCapitaTooltip.jsx b/src/js/components/homepage/visualizations/geo/tooltips/GeoCapitaTooltip.jsx index 25a6b528df..c867cff026 100644 --- a/src/js/components/homepage/visualizations/geo/tooltips/GeoCapitaTooltip.jsx +++ b/src/js/components/homepage/visualizations/geo/tooltips/GeoCapitaTooltip.jsx @@ -4,19 +4,20 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import * as MapHelper from 'helpers/mapHelper'; const propTypes = { - state: React.PropTypes.string, - value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), - y: React.PropTypes.number, - x: React.PropTypes.number, - visualization: React.PropTypes.object, - rank: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), - rankCount: React.PropTypes.number, - population: React.PropTypes.number + state: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + y: PropTypes.number, + x: PropTypes.number, + visualization: PropTypes.object, + rank: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + rankCount: PropTypes.number, + population: PropTypes.number }; export default class GeoCapitaTooltip extends React.Component { diff --git a/src/js/components/homepage/visualizations/geo/tooltips/GeoTotalTooltip.jsx b/src/js/components/homepage/visualizations/geo/tooltips/GeoTotalTooltip.jsx index 4f4f4f476a..a33ed1a6df 100644 --- a/src/js/components/homepage/visualizations/geo/tooltips/GeoTotalTooltip.jsx +++ b/src/js/components/homepage/visualizations/geo/tooltips/GeoTotalTooltip.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import * as MapHelper from 'helpers/mapHelper'; const propTypes = { - state: React.PropTypes.string, - value: React.PropTypes.number, - y: React.PropTypes.number, - x: React.PropTypes.number, - visualization: React.PropTypes.object, - total: React.PropTypes.number + state: PropTypes.string, + value: PropTypes.number, + y: PropTypes.number, + x: PropTypes.number, + visualization: PropTypes.object, + total: PropTypes.number }; export default class GeoTotalTooltip extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctionCell.jsx b/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctionCell.jsx index 9c5587317d..e7d43e9526 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctionCell.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctionCell.jsx @@ -4,31 +4,32 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { truncate } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - label: React.PropTypes.string, - value: React.PropTypes.number, - total: React.PropTypes.number, - x0: React.PropTypes.number, - x1: React.PropTypes.number, - y0: React.PropTypes.number, - functionID: React.PropTypes.number, - color: React.PropTypes.string, - strokeColor: React.PropTypes.string, - strokeOpacity: React.PropTypes.number, - toggleSubfunction: React.PropTypes.func, - toggleTooltipIn: React.PropTypes.func, - toggleTooltipOut: React.PropTypes.func, - opacity: React.PropTypes.number, - textColor: React.PropTypes.string, - textClass: React.PropTypes.string, - height: React.PropTypes.number, - width: React.PropTypes.number, - labelView: React.PropTypes.string, - percentView: React.PropTypes.string, - clickable: React.PropTypes.bool + label: PropTypes.string, + value: PropTypes.number, + total: PropTypes.number, + x0: PropTypes.number, + x1: PropTypes.number, + y0: PropTypes.number, + functionID: PropTypes.number, + color: PropTypes.string, + strokeColor: PropTypes.string, + strokeOpacity: PropTypes.number, + toggleSubfunction: PropTypes.func, + toggleTooltipIn: PropTypes.func, + toggleTooltipOut: PropTypes.func, + opacity: PropTypes.number, + textColor: PropTypes.string, + textClass: PropTypes.string, + height: PropTypes.number, + width: PropTypes.number, + labelView: PropTypes.string, + percentView: PropTypes.string, + clickable: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctions.jsx b/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctions.jsx index ab86ff362a..f0af890ac8 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctions.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetFunctions/BudgetFunctions.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { hierarchy, treemap, treemapBinary, treemapSlice } from 'd3-hierarchy'; import { throttle, find } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -12,11 +13,11 @@ import BudgetFunctionCell from './BudgetFunctionCell'; import TreeMapTooltip from '../TreeMapTooltip'; const propTypes = { - categories: React.PropTypes.object, - descriptions: React.PropTypes.array, - toggleSubfunction: React.PropTypes.func, - totalNumber: React.PropTypes.number, - showSubfunctions: React.PropTypes.bool + categories: PropTypes.object, + descriptions: PropTypes.array, + toggleSubfunction: PropTypes.func, + totalNumber: PropTypes.number, + showSubfunctions: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctions.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctions.jsx index 2d78247146..0338b7f010 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctions.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctions.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { find, remove, sumBy } from 'lodash'; import BudgetSubfunctionsNavigation from './BudgetSubfunctionsNavigation'; @@ -11,17 +12,17 @@ import BudgetSubfunctionsDescription from './BudgetSubfunctionsDescription'; import BudgetSubfunctionsMap from './BudgetSubfunctionsMap'; const propTypes = { - alternateColors: React.PropTypes.array, - categories: React.PropTypes.object, - colors: React.PropTypes.array, - descriptions: React.PropTypes.array, - selected: React.PropTypes.number, - subfunctions: React.PropTypes.object, - toggleSubfunction: React.PropTypes.func, - changeActiveSubfunction: React.PropTypes.func, - tooltipStyles: React.PropTypes.object, - totalNumber: React.PropTypes.number, - showSubfunctions: React.PropTypes.bool + alternateColors: PropTypes.array, + categories: PropTypes.object, + colors: PropTypes.array, + descriptions: PropTypes.array, + selected: PropTypes.number, + subfunctions: PropTypes.object, + toggleSubfunction: PropTypes.func, + changeActiveSubfunction: PropTypes.func, + tooltipStyles: PropTypes.object, + totalNumber: PropTypes.number, + showSubfunctions: PropTypes.bool }; export default class BudgetSubfunctions extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsDescription.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsDescription.jsx index 064db20895..cde8028a13 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsDescription.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsDescription.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - category: React.PropTypes.object, - description: React.PropTypes.object, - totalNumber: React.PropTypes.number, - subfunctionTotal: React.PropTypes.number, - numberOfSubfunctions: React.PropTypes.number + category: PropTypes.object, + description: PropTypes.object, + totalNumber: PropTypes.number, + subfunctionTotal: PropTypes.number, + numberOfSubfunctions: PropTypes.number }; export default class BudgetSubfunctionsDescription extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsMap.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsMap.jsx index 0c68a832bc..74a4f5ac44 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsMap.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsMap.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { hierarchy, treemap, treemapBinary, treemapSlice } from 'd3-hierarchy'; import { throttle, remove, sumBy, find } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -12,11 +13,11 @@ import BudgetFunctionCell from '../BudgetFunctions/BudgetFunctionCell'; import TreeMapTooltip from '../TreeMapTooltip'; const propTypes = { - category: React.PropTypes.object, - colors: React.PropTypes.array, - subfunction: React.PropTypes.object, - tooltipStyles: React.PropTypes.object, - showSubfunctions: React.PropTypes.bool + category: PropTypes.object, + colors: PropTypes.array, + subfunction: PropTypes.object, + tooltipStyles: PropTypes.object, + showSubfunctions: PropTypes.bool }; export default class BudgetSubfunctionsMap extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsNavigation.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsNavigation.jsx index dfce180233..e3336e324e 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsNavigation.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/BudgetSubfunctionsNavigation.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import MinimizedBudgetFunctions from './MinimizedBudgetFunctions/MinimizedBudgetFunctions'; @@ -11,15 +12,15 @@ import MinimizedBudgetFunctionsTooltip from './MinimizedBudgetFunctions/MinimizedBudgetFunctionsTooltip'; const propTypes = { - alternateColors: React.PropTypes.array, - categories: React.PropTypes.object, - changeActiveSubfunction: React.PropTypes.func, - colors: React.PropTypes.array, - descriptions: React.PropTypes.array, - selected: React.PropTypes.number, - toggleSubfunction: React.PropTypes.func, - tooltipStyles: React.PropTypes.object, - totalNumber: React.PropTypes.number + alternateColors: PropTypes.array, + categories: PropTypes.object, + changeActiveSubfunction: PropTypes.func, + colors: PropTypes.array, + descriptions: PropTypes.array, + selected: PropTypes.number, + toggleSubfunction: PropTypes.func, + tooltipStyles: PropTypes.object, + totalNumber: PropTypes.number }; const arrows = { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctions.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctions.jsx index 2ec8f2916b..ddf68464ef 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctions.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctions.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { hierarchy, treemap, treemapDice } from 'd3-hierarchy'; import { throttle, find } from 'lodash'; import * as MoneyFormatter from 'helpers/moneyFormatter'; @@ -12,14 +13,14 @@ import MinimizedBudgetFunctionsCell from './MinimizedBudgetFunctionsCell'; import MinimizedBudgetFunctionsTooltip from './MinimizedBudgetFunctionsTooltip'; const propTypes = { - alternateColors: React.PropTypes.array, - categories: React.PropTypes.object, - changeActiveSubfunction: React.PropTypes.func, - colors: React.PropTypes.array, - descriptions: React.PropTypes.array, - selected: React.PropTypes.number, - tooltipStyles: React.PropTypes.object, - totalNumber: React.PropTypes.number + alternateColors: PropTypes.array, + categories: PropTypes.object, + changeActiveSubfunction: PropTypes.func, + colors: PropTypes.array, + descriptions: PropTypes.array, + selected: PropTypes.number, + tooltipStyles: PropTypes.object, + totalNumber: PropTypes.number }; export default class BudgetFunctionsMinimized extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsCell.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsCell.jsx index d7ced63161..e3b601f2b6 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsCell.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsCell.jsx @@ -4,19 +4,20 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x0: React.PropTypes.number, - y0: React.PropTypes.number, - functionID: React.PropTypes.number, - color: React.PropTypes.string, - strokeColor: React.PropTypes.string, - strokeOpacity: React.PropTypes.number, - changeActiveSubfunction: React.PropTypes.func, - toggleTooltipIn: React.PropTypes.func, - toggleTooltipOut: React.PropTypes.func, - height: React.PropTypes.number, - width: React.PropTypes.number + x0: PropTypes.number, + y0: PropTypes.number, + functionID: PropTypes.number, + color: PropTypes.string, + strokeColor: PropTypes.string, + strokeOpacity: PropTypes.number, + changeActiveSubfunction: PropTypes.func, + toggleTooltipIn: PropTypes.func, + toggleTooltipOut: PropTypes.func, + height: PropTypes.number, + width: PropTypes.number }; export default class MinimizedBudgetFunctionsCell extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsTooltip.jsx b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsTooltip.jsx index 8668e847e7..79b0f3e6c2 100644 --- a/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsTooltip.jsx +++ b/src/js/components/homepage/visualizations/treemap/BudgetSubfunctions/MinimizedBudgetFunctions/MinimizedBudgetFunctionsTooltip.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - name: React.PropTypes.string, - height: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - hideArrow: React.PropTypes.bool + name: PropTypes.string, + height: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + hideArrow: PropTypes.bool }; export default class MinimizedBudgetFunctionsTooltip extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/TreeMap.jsx b/src/js/components/homepage/visualizations/treemap/TreeMap.jsx index 6d2a5502df..c7521c7a57 100644 --- a/src/js/components/homepage/visualizations/treemap/TreeMap.jsx +++ b/src/js/components/homepage/visualizations/treemap/TreeMap.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import * as Icons from 'components/sharedComponents/icons/Icons'; @@ -12,13 +13,13 @@ import BudgetSubfunctions from './BudgetSubfunctions/BudgetSubfunctions'; import TreeMapLine from './TreeMapLine'; const propTypes = { - categories: React.PropTypes.object, - colors: React.PropTypes.array, - descriptions: React.PropTypes.array, - subfunctions: React.PropTypes.object, - alternateColors: React.PropTypes.array, - tooltipStyles: React.PropTypes.object, - totalNumber: React.PropTypes.number + categories: PropTypes.object, + colors: PropTypes.array, + descriptions: PropTypes.array, + subfunctions: PropTypes.object, + alternateColors: PropTypes.array, + tooltipStyles: PropTypes.object, + totalNumber: PropTypes.number }; export default class TreeMap extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/TreeMapLabel.jsx b/src/js/components/homepage/visualizations/treemap/TreeMapLabel.jsx index 7ab917a014..7254d0494b 100644 --- a/src/js/components/homepage/visualizations/treemap/TreeMapLabel.jsx +++ b/src/js/components/homepage/visualizations/treemap/TreeMapLabel.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - labelWidth: React.PropTypes.number, - labelPadding: React.PropTypes.number, - labelDistance: React.PropTypes.number, - currentX: React.PropTypes.number, - graphWidth: React.PropTypes.number + labelWidth: PropTypes.number, + labelPadding: PropTypes.number, + labelDistance: PropTypes.number, + currentX: PropTypes.number, + graphWidth: PropTypes.number }; const defaultProps = { diff --git a/src/js/components/homepage/visualizations/treemap/TreeMapLine.jsx b/src/js/components/homepage/visualizations/treemap/TreeMapLine.jsx index 0890d025ee..7be0518910 100644 --- a/src/js/components/homepage/visualizations/treemap/TreeMapLine.jsx +++ b/src/js/components/homepage/visualizations/treemap/TreeMapLine.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import TreeMapLabel from './TreeMapLabel'; const propTypes = { - rectTransform: React.PropTypes.string, - textTransform: React.PropTypes.string, - label: React.PropTypes.string + rectTransform: PropTypes.string, + textTransform: PropTypes.string, + label: PropTypes.string }; export default class TreeMapLine extends React.Component { diff --git a/src/js/components/homepage/visualizations/treemap/TreeMapTooltip.jsx b/src/js/components/homepage/visualizations/treemap/TreeMapTooltip.jsx index 1c284e2d5c..bc9da8debb 100644 --- a/src/js/components/homepage/visualizations/treemap/TreeMapTooltip.jsx +++ b/src/js/components/homepage/visualizations/treemap/TreeMapTooltip.jsx @@ -4,21 +4,22 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - name: React.PropTypes.string, - value: React.PropTypes.string, - description: React.PropTypes.string, - height: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number, - showSub: React.PropTypes.bool, - percentage: React.PropTypes.string, - arrow: React.PropTypes.bool, - showSubfunctions: React.PropTypes.bool, - sectionHeight: React.PropTypes.number, - isSubfunctions: React.PropTypes.bool + name: PropTypes.string, + value: PropTypes.string, + description: PropTypes.string, + height: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number, + showSub: PropTypes.bool, + percentage: PropTypes.string, + arrow: PropTypes.bool, + showSubfunctions: PropTypes.bool, + sectionHeight: PropTypes.number, + isSubfunctions: PropTypes.bool }; export default class TreeMapTooltip extends React.Component { diff --git a/src/js/components/search/SearchPage.jsx b/src/js/components/search/SearchPage.jsx index 8194f30bd5..756285d6d2 100644 --- a/src/js/components/search/SearchPage.jsx +++ b/src/js/components/search/SearchPage.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import * as MetaTagHelper from 'helpers/metaTagHelper'; @@ -16,7 +17,7 @@ import SearchSidebar from './SearchSidebar'; import SearchResults from './SearchResults'; const propTypes = { - clearAllFilters: React.PropTypes.func + clearAllFilters: PropTypes.func }; export default class SearchPage extends React.Component { diff --git a/src/js/components/search/SearchResults.jsx b/src/js/components/search/SearchResults.jsx index 64770d184f..426179da25 100644 --- a/src/js/components/search/SearchResults.jsx +++ b/src/js/components/search/SearchResults.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { AddFilter, CloseCircle } from 'components/sharedComponents/icons/Icons'; @@ -20,11 +21,11 @@ import GeoVisualizationSectionContainer from import MobileFilters from './mobile/MobileFilters'; const propTypes = { - isMobile: React.PropTypes.bool, - filterCount: React.PropTypes.number, - showMobileFilters: React.PropTypes.bool, - toggleMobileFilters: React.PropTypes.func, - clearAllFilters: React.PropTypes.func + isMobile: PropTypes.bool, + filterCount: PropTypes.number, + showMobileFilters: PropTypes.bool, + toggleMobileFilters: PropTypes.func, + clearAllFilters: PropTypes.func }; export default class SearchResults extends React.Component { diff --git a/src/js/components/search/SearchSidebar.jsx b/src/js/components/search/SearchSidebar.jsx index 5408acef42..d5a26c8449 100644 --- a/src/js/components/search/SearchSidebar.jsx +++ b/src/js/components/search/SearchSidebar.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import AwardTypeContainer from 'containers/search/filters/AwardTypeContainer'; import TimePeriodContainer from 'containers/search/filters/TimePeriodContainer'; @@ -49,7 +50,7 @@ const filters = { }; const propTypes = { - mobile: React.PropTypes.bool + mobile: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/search/filters/agency/Agency.jsx b/src/js/components/search/filters/agency/Agency.jsx index e4c96a7917..7742a2562a 100644 --- a/src/js/components/search/filters/agency/Agency.jsx +++ b/src/js/components/search/filters/agency/Agency.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import AgencyListContainer from 'containers/search/filters/AgencyListContainer'; import SelectedAgencies from './SelectedAgencies'; @@ -15,10 +16,10 @@ const defaultProps = { }; const propTypes = { - toggleAgency: React.PropTypes.func, - selectedAwardingAgencies: React.PropTypes.object, - selectedFundingAgencies: React.PropTypes.object, - agencyTypes: React.PropTypes.array + toggleAgency: PropTypes.func, + selectedAwardingAgencies: PropTypes.object, + selectedFundingAgencies: PropTypes.object, + agencyTypes: PropTypes.array }; export default class Agency extends React.Component { diff --git a/src/js/components/search/filters/agency/SelectedAgencies.jsx b/src/js/components/search/filters/agency/SelectedAgencies.jsx index b84f3db70e..b8857843b5 100644 --- a/src/js/components/search/filters/agency/SelectedAgencies.jsx +++ b/src/js/components/search/filters/agency/SelectedAgencies.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { toLower } from 'lodash'; import ShownAgency from './ShownAgency'; const propTypes = { - selectedAgencies: React.PropTypes.object, - toggleAgency: React.PropTypes.func, - agencyType: React.PropTypes.string + selectedAgencies: PropTypes.object, + toggleAgency: PropTypes.func, + agencyType: PropTypes.string }; export default class SelectedAgencies extends React.Component { diff --git a/src/js/components/search/filters/agency/ShownAgency.jsx b/src/js/components/search/filters/agency/ShownAgency.jsx index 74f9585b90..2316df03aa 100644 --- a/src/js/components/search/filters/agency/ShownAgency.jsx +++ b/src/js/components/search/filters/agency/ShownAgency.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - agency: React.PropTypes.object, - toggleAgency: React.PropTypes.func, - label: React.PropTypes.string, - agencyType: React.PropTypes.string + agency: PropTypes.object, + toggleAgency: PropTypes.func, + label: PropTypes.string, + agencyType: PropTypes.string }; export default class ShownAgency extends React.Component { diff --git a/src/js/components/search/filters/awardAmount/AwardAmountItem.jsx b/src/js/components/search/filters/awardAmount/AwardAmountItem.jsx index 81d977c84c..262de4db7a 100644 --- a/src/js/components/search/filters/awardAmount/AwardAmountItem.jsx +++ b/src/js/components/search/filters/awardAmount/AwardAmountItem.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as AwardAmountHelper from 'helpers/awardAmountHelper'; const propTypes = { - awardAmounts: React.PropTypes.object, - values: React.PropTypes.array, - rangeID: React.PropTypes.string, - toggleSelection: React.PropTypes.func + awardAmounts: PropTypes.object, + values: PropTypes.array, + rangeID: PropTypes.string, + toggleSelection: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/filters/awardAmount/AwardAmountSearch.jsx b/src/js/components/search/filters/awardAmount/AwardAmountSearch.jsx index b4ad3e187d..385fc37593 100644 --- a/src/js/components/search/filters/awardAmount/AwardAmountSearch.jsx +++ b/src/js/components/search/filters/awardAmount/AwardAmountSearch.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { awardRanges, searchTypes } from 'dataMapping/search/awardAmount'; import * as AwardAmountHelper from 'helpers/awardAmountHelper'; @@ -11,9 +12,9 @@ import PrimaryCheckboxType from 'components/sharedComponents/checkbox/PrimaryChe import SpecificAwardAmountItem from './SpecificAwardAmountItem'; const propTypes = { - selectAwardRange: React.PropTypes.func, - awardAmountRanges: React.PropTypes.object, - awardAmounts: React.PropTypes.object + selectAwardRange: PropTypes.func, + awardAmountRanges: PropTypes.object, + awardAmounts: PropTypes.object }; const defaultProps = { diff --git a/src/js/components/search/filters/awardAmount/SpecificAwardAmountItem.jsx b/src/js/components/search/filters/awardAmount/SpecificAwardAmountItem.jsx index 4c7c71bad0..db0dc6e0e3 100644 --- a/src/js/components/search/filters/awardAmount/SpecificAwardAmountItem.jsx +++ b/src/js/components/search/filters/awardAmount/SpecificAwardAmountItem.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as AwardAmountHelper from 'helpers/awardAmountHelper'; import AwardAmountItem from './AwardAmountItem'; const propTypes = { - searchSpecificRange: React.PropTypes.func + searchSpecificRange: PropTypes.func }; export default class SpecificAwardAmountItem extends React.Component { diff --git a/src/js/components/search/filters/awardID/AwardIDSearch.jsx b/src/js/components/search/filters/awardID/AwardIDSearch.jsx index 680355caec..9ab075c8b0 100644 --- a/src/js/components/search/filters/awardID/AwardIDSearch.jsx +++ b/src/js/components/search/filters/awardID/AwardIDSearch.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import AwardIDListContainer from 'containers/search/filters/awardID/AwardIDListContainer'; import SelectedAwardIDs from './SelectedAwardIDs'; const propTypes = { - toggleAwardID: React.PropTypes.func, - selectedAwardIDs: React.PropTypes.object + toggleAwardID: PropTypes.func, + selectedAwardIDs: PropTypes.object }; export default class AwardIDSearch extends React.Component { diff --git a/src/js/components/search/filters/awardID/SelectedAwardIDs.jsx b/src/js/components/search/filters/awardID/SelectedAwardIDs.jsx index f37dc359aa..e7b1dc070c 100644 --- a/src/js/components/search/filters/awardID/SelectedAwardIDs.jsx +++ b/src/js/components/search/filters/awardID/SelectedAwardIDs.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as AwardIDFormatter from 'helpers/awardIDFormatter'; import ShownAwardID from './ShownAwardID'; const propTypes = { - toggleAwardID: React.PropTypes.func, - selectedAwardIDs: React.PropTypes.object + toggleAwardID: PropTypes.func, + selectedAwardIDs: PropTypes.object }; export default class SelectedAwardIDs extends React.Component { diff --git a/src/js/components/search/filters/awardID/ShownAwardID.jsx b/src/js/components/search/filters/awardID/ShownAwardID.jsx index cb4d2f05f6..94cae31382 100644 --- a/src/js/components/search/filters/awardID/ShownAwardID.jsx +++ b/src/js/components/search/filters/awardID/ShownAwardID.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - toggleAwardID: React.PropTypes.func, - label: React.PropTypes.string + toggleAwardID: PropTypes.func, + label: PropTypes.string }; export default class ShownAwardID extends React.Component { diff --git a/src/js/components/search/filters/awardType/AwardExpandButton.jsx b/src/js/components/search/filters/awardType/AwardExpandButton.jsx index f5211e18e6..13bfd22aa3 100644 --- a/src/js/components/search/filters/awardType/AwardExpandButton.jsx +++ b/src/js/components/search/filters/awardType/AwardExpandButton.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const defaultProps = { @@ -11,9 +12,9 @@ const defaultProps = { }; const propTypes = { - hidden: React.PropTypes.bool, - toggleExpand: React.PropTypes.func, - arrowState: React.PropTypes.string + hidden: PropTypes.bool, + toggleExpand: PropTypes.func, + arrowState: PropTypes.string }; export default class AwardExpandButton extends React.Component { diff --git a/src/js/components/search/filters/awardType/AwardType.jsx b/src/js/components/search/filters/awardType/AwardType.jsx index 4513642a22..e4b89da6de 100644 --- a/src/js/components/search/filters/awardType/AwardType.jsx +++ b/src/js/components/search/filters/awardType/AwardType.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { awardTypeGroups, awardTypeCodes } from 'dataMapping/search/awardType'; import PrimaryCheckboxType from 'components/sharedComponents/checkbox/PrimaryCheckboxType'; @@ -40,9 +41,9 @@ const defaultProps = { }; const propTypes = { - awardTypes: React.PropTypes.arrayOf(React.PropTypes.object), - awardType: React.PropTypes.object, - bulkTypeChange: React.PropTypes.func + awardTypes: PropTypes.arrayOf(PropTypes.object), + awardType: PropTypes.object, + bulkTypeChange: PropTypes.func }; export default class AwardType extends React.Component { diff --git a/src/js/components/search/filters/budgetCategory/BudgetCategoryOCSearch.jsx b/src/js/components/search/filters/budgetCategory/BudgetCategoryOCSearch.jsx index 20e66d73a9..66d54ff135 100644 --- a/src/js/components/search/filters/budgetCategory/BudgetCategoryOCSearch.jsx +++ b/src/js/components/search/filters/budgetCategory/BudgetCategoryOCSearch.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { objectClassDefinitions, objectClassDefinitionsGroups } from 'dataMapping/search/budgetCategory'; @@ -40,9 +41,9 @@ const defaultProps = { }; const propTypes = { - objectClassMapping: React.PropTypes.arrayOf(React.PropTypes.object), - objectClasses: React.PropTypes.object, - selectObjectClass: React.PropTypes.func + objectClassMapping: PropTypes.arrayOf(PropTypes.object), + objectClasses: PropTypes.object, + selectObjectClass: PropTypes.func }; export default class BudgetCategoryOCSearch extends React.Component { diff --git a/src/js/components/search/filters/budgetCategory/BudgetCategorySearch.jsx b/src/js/components/search/filters/budgetCategory/BudgetCategorySearch.jsx index a6cff59b56..dd0cc1681c 100644 --- a/src/js/components/search/filters/budgetCategory/BudgetCategorySearch.jsx +++ b/src/js/components/search/filters/budgetCategory/BudgetCategorySearch.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BudgetCategoryFunctionContainer from 'containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer'; @@ -16,10 +17,10 @@ import SelectedBudgetFunctions from './SelectedBudgetFunctions'; import SelectedFederalAccounts from './SelectedFederalAccounts'; const propTypes = { - updateSelectedBudgetFunctions: React.PropTypes.func, - updateSelectedFederalAccounts: React.PropTypes.func, - budgetFunctions: React.PropTypes.object, - federalAccounts: React.PropTypes.object + updateSelectedBudgetFunctions: PropTypes.func, + updateSelectedFederalAccounts: PropTypes.func, + budgetFunctions: PropTypes.object, + federalAccounts: PropTypes.object }; export default class BudgetCategorySearch extends React.Component { diff --git a/src/js/components/search/filters/budgetCategory/ObjectClassItem.jsx b/src/js/components/search/filters/budgetCategory/ObjectClassItem.jsx index 3ea252f394..d922751ab6 100644 --- a/src/js/components/search/filters/budgetCategory/ObjectClassItem.jsx +++ b/src/js/components/search/filters/budgetCategory/ObjectClassItem.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - objectClasses: React.PropTypes.object, - objectClassLabel: React.PropTypes.string, - objectClassID: React.PropTypes.number, - toggleSelection: React.PropTypes.func + objectClasses: PropTypes.object, + objectClassLabel: PropTypes.string, + objectClassID: PropTypes.number, + toggleSelection: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/filters/budgetCategory/SelectedBudgetFunctions.jsx b/src/js/components/search/filters/budgetCategory/SelectedBudgetFunctions.jsx index 2ef8b07de7..19550c0a95 100644 --- a/src/js/components/search/filters/budgetCategory/SelectedBudgetFunctions.jsx +++ b/src/js/components/search/filters/budgetCategory/SelectedBudgetFunctions.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as BudgetCategoryHelper from 'helpers/budgetCategoryHelper'; import ShownBudgetFunction from './ShownBudgetFunction'; const propTypes = { - budgetFunctions: React.PropTypes.object, - updateSelectedBudgetFunctions: React.PropTypes.func + budgetFunctions: PropTypes.object, + updateSelectedBudgetFunctions: PropTypes.func }; export default class SelectedBudgetCategories extends React.Component { diff --git a/src/js/components/search/filters/budgetCategory/SelectedFederalAccounts.jsx b/src/js/components/search/filters/budgetCategory/SelectedFederalAccounts.jsx index 2037adfd58..4949ede69a 100644 --- a/src/js/components/search/filters/budgetCategory/SelectedFederalAccounts.jsx +++ b/src/js/components/search/filters/budgetCategory/SelectedFederalAccounts.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ShownFederalAccount from './ShownFederalAccount'; const propTypes = { - federalAccounts: React.PropTypes.object, - updateSelectedFederalAccounts: React.PropTypes.func + federalAccounts: PropTypes.object, + updateSelectedFederalAccounts: PropTypes.func }; export default class SelectedFederalAccounts extends React.Component { diff --git a/src/js/components/search/filters/budgetCategory/ShownBudgetFunction.jsx b/src/js/components/search/filters/budgetCategory/ShownBudgetFunction.jsx index 0de2e7f962..48e1860f10 100644 --- a/src/js/components/search/filters/budgetCategory/ShownBudgetFunction.jsx +++ b/src/js/components/search/filters/budgetCategory/ShownBudgetFunction.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - updateSelectedBudgetFunctions: React.PropTypes.func, - label: React.PropTypes.string + updateSelectedBudgetFunctions: PropTypes.func, + label: PropTypes.string }; export default class ShownBudgetFunction extends React.Component { diff --git a/src/js/components/search/filters/budgetCategory/ShownFederalAccount.jsx b/src/js/components/search/filters/budgetCategory/ShownFederalAccount.jsx index d9ce68dd25..9b19336a87 100644 --- a/src/js/components/search/filters/budgetCategory/ShownFederalAccount.jsx +++ b/src/js/components/search/filters/budgetCategory/ShownFederalAccount.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - updateSelectedFederalAccounts: React.PropTypes.func, - label: React.PropTypes.string + updateSelectedFederalAccounts: PropTypes.func, + label: PropTypes.string }; export default class ShownFederalAccount extends React.Component { diff --git a/src/js/components/search/filters/keyword/Keyword.jsx b/src/js/components/search/filters/keyword/Keyword.jsx index 6b5405659c..68f8d618d8 100644 --- a/src/js/components/search/filters/keyword/Keyword.jsx +++ b/src/js/components/search/filters/keyword/Keyword.jsx @@ -4,11 +4,12 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - submitText: React.PropTypes.func, - changedInput: React.PropTypes.func, - value: React.PropTypes.string + submitText: PropTypes.func, + changedInput: PropTypes.func, + value: PropTypes.string }; export default class Keyword extends React.Component { diff --git a/src/js/components/search/filters/location/CountryType.jsx b/src/js/components/search/filters/location/CountryType.jsx index f6ea778371..db77818933 100644 --- a/src/js/components/search/filters/location/CountryType.jsx +++ b/src/js/components/search/filters/location/CountryType.jsx @@ -4,11 +4,12 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - toggleCountry: React.PropTypes.func, - countries: React.PropTypes.array, - locationDomesticForeign: React.PropTypes.string + toggleCountry: PropTypes.func, + countries: PropTypes.array, + locationDomesticForeign: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/search/filters/location/LocationSearch.jsx b/src/js/components/search/filters/location/LocationSearch.jsx index cdf3380d54..2ee81770ed 100644 --- a/src/js/components/search/filters/location/LocationSearch.jsx +++ b/src/js/components/search/filters/location/LocationSearch.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import LocationListContainer from 'containers/search/filters/location/LocationListContainer'; import CountryType from './CountryType'; import SelectedLocations from './SelectedLocations'; const propTypes = { - selectLocation: React.PropTypes.func, - removeLocation: React.PropTypes.func, - selectedLocations: React.PropTypes.object + selectLocation: PropTypes.func, + removeLocation: PropTypes.func, + selectedLocations: PropTypes.object }; export default class LocationSearch extends React.Component { diff --git a/src/js/components/search/filters/location/SelectedLocations.jsx b/src/js/components/search/filters/location/SelectedLocations.jsx index 7a3d0ff032..7c107f08fd 100644 --- a/src/js/components/search/filters/location/SelectedLocations.jsx +++ b/src/js/components/search/filters/location/SelectedLocations.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as LocationFormatter from 'helpers/locationFormatter'; import ShownLocation from './ShownLocation'; const propTypes = { - selectedLocations: React.PropTypes.object, - removeLocation: React.PropTypes.func + selectedLocations: PropTypes.object, + removeLocation: PropTypes.func }; export default class SelectedLocations extends React.Component { diff --git a/src/js/components/search/filters/location/ShownLocation.jsx b/src/js/components/search/filters/location/ShownLocation.jsx index a721ebd683..8f43e27d2f 100644 --- a/src/js/components/search/filters/location/ShownLocation.jsx +++ b/src/js/components/search/filters/location/ShownLocation.jsx @@ -4,11 +4,12 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - removeLocation: React.PropTypes.func, - label: React.PropTypes.string + removeLocation: PropTypes.func, + label: PropTypes.string }; export default class ShownLocation extends React.Component { diff --git a/src/js/components/search/filters/recipient/RecipientSearch.jsx b/src/js/components/search/filters/recipient/RecipientSearch.jsx index 4c4798f0ad..173dca6f99 100644 --- a/src/js/components/search/filters/recipient/RecipientSearch.jsx +++ b/src/js/components/search/filters/recipient/RecipientSearch.jsx @@ -3,6 +3,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import RecipientNameDUNSContainer from 'containers/search/filters/recipient/RecipientNameDUNSContainer'; @@ -14,12 +15,12 @@ import SelectedRecipients from './SelectedRecipients'; import SelectedRecipientLocations from './SelectedRecipientLocations'; const propTypes = { - toggleRecipient: React.PropTypes.func, - toggleDomesticForeign: React.PropTypes.func, - toggleRecipientType: React.PropTypes.func, - toggleRecipientLocation: React.PropTypes.func, - selectedRecipients: React.PropTypes.object, - selectedRecipientLocations: React.PropTypes.object + toggleRecipient: PropTypes.func, + toggleDomesticForeign: PropTypes.func, + toggleRecipientType: PropTypes.func, + toggleRecipientLocation: PropTypes.func, + selectedRecipients: PropTypes.object, + selectedRecipientLocations: PropTypes.object }; export default class RecipientSearch extends React.Component { diff --git a/src/js/components/search/filters/recipient/RecipientToggle.jsx b/src/js/components/search/filters/recipient/RecipientToggle.jsx index 804b5e6a93..d1c152d010 100644 --- a/src/js/components/search/filters/recipient/RecipientToggle.jsx +++ b/src/js/components/search/filters/recipient/RecipientToggle.jsx @@ -3,11 +3,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - toggleDomesticForeign: React.PropTypes.func, - countries: React.PropTypes.array, - recipientDomesticForeign: React.PropTypes.string + toggleDomesticForeign: PropTypes.func, + countries: PropTypes.array, + recipientDomesticForeign: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/search/filters/recipient/RecipientType.jsx b/src/js/components/search/filters/recipient/RecipientType.jsx index d74e0c7136..480787ae69 100644 --- a/src/js/components/search/filters/recipient/RecipientType.jsx +++ b/src/js/components/search/filters/recipient/RecipientType.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { recipientTypes, recipientTypeGroups } from 'dataMapping/search/recipientType'; import PrimaryCheckboxType from 'components/sharedComponents/checkbox/PrimaryCheckboxType'; @@ -60,8 +61,8 @@ const defaultProps = { }; const propTypes = { - recipientTypeMapping: React.PropTypes.arrayOf(React.PropTypes.object), - recipientType: React.PropTypes.object + recipientTypeMapping: PropTypes.arrayOf(PropTypes.object), + recipientType: PropTypes.object }; export default class RecipientType extends React.Component { diff --git a/src/js/components/search/filters/recipient/SelectedRecipientLocations.jsx b/src/js/components/search/filters/recipient/SelectedRecipientLocations.jsx index 0e02db4bcb..ff10d04e3d 100644 --- a/src/js/components/search/filters/recipient/SelectedRecipientLocations.jsx +++ b/src/js/components/search/filters/recipient/SelectedRecipientLocations.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as LocationFormatter from 'helpers/locationFormatter'; import ShownRecipientLocation from './ShownRecipientLocation'; const propTypes = { - selectedRecipientLocations: React.PropTypes.object, - toggleRecipientLocation: React.PropTypes.func + selectedRecipientLocations: PropTypes.object, + toggleRecipientLocation: PropTypes.func }; export default class SelectedRecipientLocations extends React.Component { diff --git a/src/js/components/search/filters/recipient/SelectedRecipients.jsx b/src/js/components/search/filters/recipient/SelectedRecipients.jsx index 58caa89326..797fc65bc6 100644 --- a/src/js/components/search/filters/recipient/SelectedRecipients.jsx +++ b/src/js/components/search/filters/recipient/SelectedRecipients.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ShownRecipient from './ShownRecipient'; const propTypes = { - selectedRecipients: React.PropTypes.object, - toggleRecipient: React.PropTypes.func + selectedRecipients: PropTypes.object, + toggleRecipient: PropTypes.func }; export default class SelectedRecipients extends React.Component { diff --git a/src/js/components/search/filters/recipient/ShownRecipient.jsx b/src/js/components/search/filters/recipient/ShownRecipient.jsx index 483ac7a407..326e60b938 100644 --- a/src/js/components/search/filters/recipient/ShownRecipient.jsx +++ b/src/js/components/search/filters/recipient/ShownRecipient.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - toggleRecipient: React.PropTypes.func, - label: React.PropTypes.string + toggleRecipient: PropTypes.func, + label: PropTypes.string }; export default class ShownRecipient extends React.Component { diff --git a/src/js/components/search/filters/recipient/ShownRecipientLocation.jsx b/src/js/components/search/filters/recipient/ShownRecipientLocation.jsx index 8057e0d013..2f5ec3d737 100644 --- a/src/js/components/search/filters/recipient/ShownRecipientLocation.jsx +++ b/src/js/components/search/filters/recipient/ShownRecipientLocation.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - toggleLocation: React.PropTypes.func, - label: React.PropTypes.string + toggleLocation: PropTypes.func, + label: PropTypes.string }; export default class ShownRecipientLocation extends React.Component { diff --git a/src/js/components/search/filters/timePeriod/AllFiscalYears.jsx b/src/js/components/search/filters/timePeriod/AllFiscalYears.jsx index 713e2c3cac..65929f40dd 100644 --- a/src/js/components/search/filters/timePeriod/AllFiscalYears.jsx +++ b/src/js/components/search/filters/timePeriod/AllFiscalYears.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { Set } from 'immutable'; import FiscalYear from './FiscalYear'; const propTypes = { - timePeriods: React.PropTypes.array, - selectedFY: React.PropTypes.object, - updateFilter: React.PropTypes.func + timePeriods: PropTypes.array, + selectedFY: PropTypes.object, + updateFilter: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/components/search/filters/timePeriod/DateRange.jsx b/src/js/components/search/filters/timePeriod/DateRange.jsx index dc879da41b..98c1bb68e7 100644 --- a/src/js/components/search/filters/timePeriod/DateRange.jsx +++ b/src/js/components/search/filters/timePeriod/DateRange.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import DatePicker from 'components/sharedComponents/DatePicker'; const defaultProps = { @@ -13,12 +14,12 @@ const defaultProps = { }; const propTypes = { - startingTab: React.PropTypes.number, - onDateChange: React.PropTypes.func, - startDate: React.PropTypes.object, - endDate: React.PropTypes.object, - showError: React.PropTypes.func, - hideError: React.PropTypes.func + startingTab: PropTypes.number, + onDateChange: PropTypes.func, + startDate: PropTypes.object, + endDate: PropTypes.object, + showError: PropTypes.func, + hideError: PropTypes.func }; export default class DateRange extends React.Component { diff --git a/src/js/components/search/filters/timePeriod/DateRangeError.jsx b/src/js/components/search/filters/timePeriod/DateRangeError.jsx index 4d8398a6a2..ba1697862b 100644 --- a/src/js/components/search/filters/timePeriod/DateRangeError.jsx +++ b/src/js/components/search/filters/timePeriod/DateRangeError.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from '../../../sharedComponents/icons/Icons'; const defaultProps = { @@ -12,8 +13,8 @@ const defaultProps = { }; const propTypes = { - header: React.PropTypes.string, - message: React.PropTypes.string + header: PropTypes.string, + message: PropTypes.string }; export default class DateRangeError extends React.Component { diff --git a/src/js/components/search/filters/timePeriod/FiscalYear.jsx b/src/js/components/search/filters/timePeriod/FiscalYear.jsx index beb3eddf7e..78e9204042 100644 --- a/src/js/components/search/filters/timePeriod/FiscalYear.jsx +++ b/src/js/components/search/filters/timePeriod/FiscalYear.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - year: React.PropTypes.string, - saveSelectedYear: React.PropTypes.func, - checked: React.PropTypes.bool, - saveAllYears: React.PropTypes.func + year: PropTypes.string, + saveSelectedYear: PropTypes.func, + checked: PropTypes.bool, + saveAllYears: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/filters/timePeriod/TimePeriod.jsx b/src/js/components/search/filters/timePeriod/TimePeriod.jsx index 8763fced5f..d361a749fc 100644 --- a/src/js/components/search/filters/timePeriod/TimePeriod.jsx +++ b/src/js/components/search/filters/timePeriod/TimePeriod.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import moment from 'moment'; import { Set } from 'immutable'; import DateRange from './DateRange'; @@ -16,16 +17,16 @@ const defaultProps = { }; const propTypes = { - filterTimePeriodFY: React.PropTypes.instanceOf(Set), - filterTimePeriodStart: React.PropTypes.string, - filterTimePeriodEnd: React.PropTypes.string, - filterTimePeriodType: React.PropTypes.string, - label: React.PropTypes.string, - timePeriods: React.PropTypes.array, - activeTab: React.PropTypes.string, - updateFilter: React.PropTypes.func, - changeTab: React.PropTypes.func, - disableDateRange: React.PropTypes.bool + filterTimePeriodFY: PropTypes.instanceOf(Set), + filterTimePeriodStart: PropTypes.string, + filterTimePeriodEnd: PropTypes.string, + filterTimePeriodType: PropTypes.string, + label: PropTypes.string, + timePeriods: PropTypes.array, + activeTab: PropTypes.string, + updateFilter: PropTypes.func, + changeTab: PropTypes.func, + disableDateRange: PropTypes.bool }; const ga = require('react-ga'); diff --git a/src/js/components/search/header/FormatItem.jsx b/src/js/components/search/header/FormatItem.jsx index 6e1140e767..33e12de03c 100644 --- a/src/js/components/search/header/FormatItem.jsx +++ b/src/js/components/search/header/FormatItem.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import $ from 'jquery'; const defaultProps = { @@ -11,11 +12,11 @@ const defaultProps = { }; const propTypes = { - code: React.PropTypes.string.isRequired, - currentSection: React.PropTypes.string.isRequired, - icon: React.PropTypes.element.isRequired, - label: React.PropTypes.string.isRequired, - accessibleLabel: React.PropTypes.string.isRequired + code: PropTypes.string.isRequired, + currentSection: PropTypes.string.isRequired, + icon: PropTypes.element.isRequired, + label: PropTypes.string.isRequired, + accessibleLabel: PropTypes.string.isRequired }; export default class FormatItem extends React.Component { diff --git a/src/js/components/search/header/SearchHeader.jsx b/src/js/components/search/header/SearchHeader.jsx index a92e7a6527..42a0f8a1d7 100644 --- a/src/js/components/search/header/SearchHeader.jsx +++ b/src/js/components/search/header/SearchHeader.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; @@ -11,8 +12,8 @@ import FormatItem from './FormatItem'; import DownloadButton from './DownloadButton'; const propTypes = { - isSticky: React.PropTypes.bool, - currentSection: React.PropTypes.string + isSticky: PropTypes.bool, + currentSection: PropTypes.string }; export default class SearchHeader extends React.Component { diff --git a/src/js/components/search/mobile/MobileFilterHeader.jsx b/src/js/components/search/mobile/MobileFilterHeader.jsx index a414c62c85..cab66431cf 100644 --- a/src/js/components/search/mobile/MobileFilterHeader.jsx +++ b/src/js/components/search/mobile/MobileFilterHeader.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { ArrowUp } from 'components/sharedComponents/icons/Icons'; const propTypes = { - toggleMobileFilters: React.PropTypes.func, - filterCount: React.PropTypes.number + toggleMobileFilters: PropTypes.func, + filterCount: PropTypes.number }; export default class MobileFilterHeader extends React.Component { diff --git a/src/js/components/search/mobile/MobileFilters.jsx b/src/js/components/search/mobile/MobileFilters.jsx index dcb970160b..c2efaee67c 100644 --- a/src/js/components/search/mobile/MobileFilters.jsx +++ b/src/js/components/search/mobile/MobileFilters.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup'; import SearchSidebar from '../SearchSidebar'; const propTypes = { - showMobileFilters: React.PropTypes.bool, - filterCount: React.PropTypes.number, - toggleMobileFilters: React.PropTypes.func + showMobileFilters: PropTypes.bool, + filterCount: PropTypes.number, + toggleMobileFilters: PropTypes.func }; export default class MobileFilters extends React.Component { diff --git a/src/js/components/search/modals/DownloadLocation.jsx b/src/js/components/search/modals/DownloadLocation.jsx index 2a8bc37aee..bfe2ff9390 100644 --- a/src/js/components/search/modals/DownloadLocation.jsx +++ b/src/js/components/search/modals/DownloadLocation.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Clipboard from 'clipboard'; const propTypes = { - location: React.PropTypes.string + location: PropTypes.string }; export default class DownloadLocation extends React.Component { diff --git a/src/js/components/search/modals/ExtraModal.jsx b/src/js/components/search/modals/ExtraModal.jsx index a2e5aff210..3a9c1826ef 100644 --- a/src/js/components/search/modals/ExtraModal.jsx +++ b/src/js/components/search/modals/ExtraModal.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Modal from 'react-aria-modal'; import { Close } from 'components/sharedComponents/icons/Icons'; @@ -13,12 +14,12 @@ import CylonEye from './CylonEye'; import DownloadLocation from './DownloadLocation'; const propTypes = { - mounted: React.PropTypes.bool, - hideModal: React.PropTypes.func, - title: React.PropTypes.string, - message: React.PropTypes.string, - location: React.PropTypes.string, - animate: React.PropTypes.bool + mounted: PropTypes.bool, + hideModal: PropTypes.func, + title: PropTypes.string, + message: PropTypes.string, + location: PropTypes.string, + animate: PropTypes.bool }; export default class ExtraModal extends React.Component { diff --git a/src/js/components/search/table/ResultsColumnOption.jsx b/src/js/components/search/table/ResultsColumnOption.jsx index f3998db10f..1e94674ff5 100644 --- a/src/js/components/search/table/ResultsColumnOption.jsx +++ b/src/js/components/search/table/ResultsColumnOption.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - checked: React.PropTypes.string, - column: React.PropTypes.string, - label: React.PropTypes.string, - toggleColumnVisibility: React.PropTypes.func + checked: PropTypes.string, + column: PropTypes.string, + label: PropTypes.string, + toggleColumnVisibility: PropTypes.func }; export default class ResultsColumnOption extends React.Component { diff --git a/src/js/components/search/table/ResultsColumnVisibleOption.jsx b/src/js/components/search/table/ResultsColumnVisibleOption.jsx index de19138cd1..e4ebe3c0e3 100644 --- a/src/js/components/search/table/ResultsColumnVisibleOption.jsx +++ b/src/js/components/search/table/ResultsColumnVisibleOption.jsx @@ -5,6 +5,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { findDOMNode } from 'react-dom'; import { DragSource, DropTarget } from 'react-dnd'; @@ -13,16 +14,16 @@ import * as Icons from 'components/sharedComponents/icons/Icons'; import ItemTypes from './ItemTypes'; const propTypes = { - checked: React.PropTypes.string, - column: React.PropTypes.string, - label: React.PropTypes.string, - toggleColumnVisibility: React.PropTypes.func, - connectDragSource: React.PropTypes.func.isRequired, - connectDropTarget: React.PropTypes.func.isRequired, - index: React.PropTypes.number.isRequired, - isDragging: React.PropTypes.bool.isRequired, - id: React.PropTypes.any.isRequired, - moveColumn: React.PropTypes.func.isRequired + checked: PropTypes.string, + column: PropTypes.string, + label: PropTypes.string, + toggleColumnVisibility: PropTypes.func, + connectDragSource: PropTypes.func.isRequired, + connectDropTarget: PropTypes.func.isRequired, + index: PropTypes.number.isRequired, + isDragging: PropTypes.bool.isRequired, + id: PropTypes.any.isRequired, + moveColumn: PropTypes.func.isRequired }; const columnSource = { diff --git a/src/js/components/search/table/ResultsSelectColumns.jsx b/src/js/components/search/table/ResultsSelectColumns.jsx index 56a05e8bb6..01470d13ae 100644 --- a/src/js/components/search/table/ResultsSelectColumns.jsx +++ b/src/js/components/search/table/ResultsSelectColumns.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { DragDropContext } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; import * as Icons from 'components/sharedComponents/icons/Icons'; @@ -12,10 +13,10 @@ import ResultsColumnOption from './ResultsColumnOption'; import ResultsColumnVisibleOption from './ResultsColumnVisibleOption'; const propTypes = { - columns: React.PropTypes.array, - hiddenColumns: React.PropTypes.array, - toggleColumnVisibility: React.PropTypes.func, - reorderColumns: React.PropTypes.func + columns: PropTypes.array, + hiddenColumns: PropTypes.array, + toggleColumnVisibility: PropTypes.func, + reorderColumns: PropTypes.func }; class ResultsSelectColumns extends React.Component { diff --git a/src/js/components/search/table/ResultsTable.jsx b/src/js/components/search/table/ResultsTable.jsx index 463054b97a..13127dc2cb 100644 --- a/src/js/components/search/table/ResultsTable.jsx +++ b/src/js/components/search/table/ResultsTable.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import Immutable, { OrderedSet } from 'immutable'; import IBTable from 'components/sharedComponents/IBTable/IBTable'; @@ -12,13 +13,13 @@ import ResultsTableGenericCell from './cells/ResultsTableGenericCell'; import ResultsTableAwardIdCell from './cells/ResultsTableAwardIdCell'; const propTypes = { - results: React.PropTypes.array, - batch: React.PropTypes.object, - columns: React.PropTypes.array, - headerCellClass: React.PropTypes.func.isRequired, - visibleWidth: React.PropTypes.number, - loadNextPage: React.PropTypes.func, - currentType: React.PropTypes.string + results: PropTypes.array, + batch: PropTypes.object, + columns: PropTypes.array, + headerCellClass: PropTypes.func.isRequired, + visibleWidth: PropTypes.number, + loadNextPage: PropTypes.func, + currentType: PropTypes.string }; const rowHeight = 40; diff --git a/src/js/components/search/table/ResultsTableMessage.jsx b/src/js/components/search/table/ResultsTableMessage.jsx index ca2da1baae..86184d79fc 100644 --- a/src/js/components/search/table/ResultsTableMessage.jsx +++ b/src/js/components/search/table/ResultsTableMessage.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const defaultProps = { message: '' }; const propTypes = { - message: React.PropTypes.string + message: PropTypes.string }; export default class ResultsTableMessage extends React.Component { diff --git a/src/js/components/search/table/ResultsTablePicker.jsx b/src/js/components/search/table/ResultsTablePicker.jsx index feff7d578a..7327ac61f5 100644 --- a/src/js/components/search/table/ResultsTablePicker.jsx +++ b/src/js/components/search/table/ResultsTablePicker.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import ResultsTablePickerOption from './ResultsTablePickerOption'; const propTypes = { - types: React.PropTypes.array, - active: React.PropTypes.string, - switchTab: React.PropTypes.func + types: PropTypes.array, + active: PropTypes.string, + switchTab: PropTypes.func }; export default class ResultsTablePicker extends React.Component { diff --git a/src/js/components/search/table/ResultsTablePickerOption.jsx b/src/js/components/search/table/ResultsTablePickerOption.jsx index db87a3a890..aa0f7dbfd5 100644 --- a/src/js/components/search/table/ResultsTablePickerOption.jsx +++ b/src/js/components/search/table/ResultsTablePickerOption.jsx @@ -4,16 +4,17 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; const propTypes = { - label: React.PropTypes.string, - internal: React.PropTypes.string, - active: React.PropTypes.bool, - enabled: React.PropTypes.bool, - switchTab: React.PropTypes.func, - togglePicker: React.PropTypes.func + label: PropTypes.string, + internal: PropTypes.string, + active: PropTypes.bool, + enabled: PropTypes.bool, + switchTab: PropTypes.func, + togglePicker: PropTypes.func }; export default class ResultsTablePickerOption extends React.Component { diff --git a/src/js/components/search/table/ResultsTableSection.jsx b/src/js/components/search/table/ResultsTableSection.jsx index f61830e24b..4a17d15396 100644 --- a/src/js/components/search/table/ResultsTableSection.jsx +++ b/src/js/components/search/table/ResultsTableSection.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import ResultsTableHeaderCellContainer from 'containers/search/table/ResultsTableHeaderCellContainer'; @@ -18,16 +19,16 @@ import ResultsTablePicker from './ResultsTablePicker'; import ResultsSelectColumns from './ResultsSelectColumns'; const propTypes = { - inFlight: React.PropTypes.bool, - tableTypes: React.PropTypes.array, - currentType: React.PropTypes.string, - switchTab: React.PropTypes.func, - results: React.PropTypes.array, - columns: React.PropTypes.array, - hiddenColumns: React.PropTypes.array, - toggleColumnVisibility: React.PropTypes.func, - reorderColumns: React.PropTypes.func, - lastReq: React.PropTypes.string + inFlight: PropTypes.bool, + tableTypes: PropTypes.array, + currentType: PropTypes.string, + switchTab: PropTypes.func, + results: PropTypes.array, + columns: PropTypes.array, + hiddenColumns: PropTypes.array, + toggleColumnVisibility: PropTypes.func, + reorderColumns: PropTypes.func, + lastReq: PropTypes.string }; export default class ResultsTableSection extends React.Component { diff --git a/src/js/components/search/table/ResultsTableTabItem.jsx b/src/js/components/search/table/ResultsTableTabItem.jsx index cebb6ce55c..57f9f250a3 100644 --- a/src/js/components/search/table/ResultsTableTabItem.jsx +++ b/src/js/components/search/table/ResultsTableTabItem.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; const propTypes = { - label: React.PropTypes.string, - internal: React.PropTypes.string, - active: React.PropTypes.bool, - enabled: React.PropTypes.bool, - switchTab: React.PropTypes.func + label: PropTypes.string, + internal: PropTypes.string, + active: PropTypes.bool, + enabled: PropTypes.bool, + switchTab: PropTypes.func }; export default class ResultsTableTabItem extends React.Component { diff --git a/src/js/components/search/table/ResultsTableTabs.jsx b/src/js/components/search/table/ResultsTableTabs.jsx index ac27cc9838..7ff0655d41 100644 --- a/src/js/components/search/table/ResultsTableTabs.jsx +++ b/src/js/components/search/table/ResultsTableTabs.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import ResultsTableTabItem from './ResultsTableTabItem'; const propTypes = { - types: React.PropTypes.array, - active: React.PropTypes.string, - switchTab: React.PropTypes.func + types: PropTypes.array, + active: PropTypes.string, + switchTab: PropTypes.func }; export default class ResultsTableTabs extends React.Component { diff --git a/src/js/components/search/table/cells/ResultsTableAwardIdCell.jsx b/src/js/components/search/table/cells/ResultsTableAwardIdCell.jsx index d5cda60211..5f38d43aa5 100644 --- a/src/js/components/search/table/cells/ResultsTableAwardIdCell.jsx +++ b/src/js/components/search/table/cells/ResultsTableAwardIdCell.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - data: React.PropTypes.string, - rowIndex: React.PropTypes.number, - column: React.PropTypes.string, - isLastColumn: React.PropTypes.bool, - id: React.PropTypes.number + data: PropTypes.string, + rowIndex: PropTypes.number, + column: PropTypes.string, + isLastColumn: PropTypes.bool, + id: PropTypes.number }; export default class ResultsTableAwardIdCell extends React.Component { diff --git a/src/js/components/search/table/cells/ResultsTableGenericCell.jsx b/src/js/components/search/table/cells/ResultsTableGenericCell.jsx index 8328a8110a..a90ad67329 100644 --- a/src/js/components/search/table/cells/ResultsTableGenericCell.jsx +++ b/src/js/components/search/table/cells/ResultsTableGenericCell.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - data: React.PropTypes.string, - rowIndex: React.PropTypes.number, - column: React.PropTypes.string, - isLastColumn: React.PropTypes.bool + data: PropTypes.string, + rowIndex: PropTypes.number, + column: PropTypes.string, + isLastColumn: PropTypes.bool }; export default class ResultsTableGenericCell extends React.Component { diff --git a/src/js/components/search/table/cells/ResultsTableHeaderCell.jsx b/src/js/components/search/table/cells/ResultsTableHeaderCell.jsx index f724446662..363fd03a8d 100644 --- a/src/js/components/search/table/cells/ResultsTableHeaderCell.jsx +++ b/src/js/components/search/table/cells/ResultsTableHeaderCell.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - label: React.PropTypes.string, - column: React.PropTypes.string, - defaultDirection: React.PropTypes.string, - order: React.PropTypes.object, - setSearchOrder: React.PropTypes.func, - isLastColumn: React.PropTypes.bool + label: PropTypes.string, + column: PropTypes.string, + defaultDirection: PropTypes.string, + order: PropTypes.object, + setSearchOrder: PropTypes.func, + isLastColumn: PropTypes.bool }; export default class ResultsTableHeaderCell extends React.Component { diff --git a/src/js/components/search/topFilterBar/TopFilterBar.jsx b/src/js/components/search/topFilterBar/TopFilterBar.jsx index 937bc2ee03..871ebbf9e6 100644 --- a/src/js/components/search/topFilterBar/TopFilterBar.jsx +++ b/src/js/components/search/topFilterBar/TopFilterBar.jsx @@ -9,14 +9,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - filters: React.PropTypes.array, - filterCount: React.PropTypes.number, - clearAllFilters: React.PropTypes.func, - groupGenerator: React.PropTypes.func + filters: PropTypes.array, + filterCount: PropTypes.number, + clearAllFilters: PropTypes.func, + groupGenerator: PropTypes.func }; export default class TopFilterBar extends React.Component { diff --git a/src/js/components/search/topFilterBar/TopFilterItem.jsx b/src/js/components/search/topFilterBar/TopFilterItem.jsx index 425f490f65..b9f6c5363e 100644 --- a/src/js/components/search/topFilterBar/TopFilterItem.jsx +++ b/src/js/components/search/topFilterBar/TopFilterItem.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - title: React.PropTypes.string.isRequired, - value: React.PropTypes.any, - removeFilter: React.PropTypes.func + title: PropTypes.string.isRequired, + value: PropTypes.any, + removeFilter: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/topFilterBar/filterGroups/AgencyFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/AgencyFilterGroup.jsx index 6cd3e40171..4dea974634 100644 --- a/src/js/components/search/topFilterBar/filterGroups/AgencyFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/AgencyFilterGroup.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class AgencyFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/AwardAmountFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/AwardAmountFilterGroup.jsx index d9b5ecf1b6..8855738e46 100644 --- a/src/js/components/search/topFilterBar/filterGroups/AwardAmountFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/AwardAmountFilterGroup.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as AwardAmountFormatter from 'helpers/awardAmountHelper'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class AwardAmountFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/AwardIDFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/AwardIDFilterGroup.jsx index dac08e23ad..3c44e99c05 100644 --- a/src/js/components/search/topFilterBar/filterGroups/AwardIDFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/AwardIDFilterGroup.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as AwardIDFormatter from 'helpers/awardIDFormatter'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class AwardIDFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/AwardTypeFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/AwardTypeFilterGroup.jsx index 5c2f59159b..1652efe2f1 100644 --- a/src/js/components/search/topFilterBar/filterGroups/AwardTypeFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/AwardTypeFilterGroup.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { indexOf, difference, concat } from 'lodash'; import { Set } from 'immutable'; @@ -13,8 +14,8 @@ import * as AwardType from 'dataMapping/search/awardType'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; const groupKeys = ['contracts', 'grants', 'direct_payments', 'loans']; diff --git a/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx index b1ed8d38ef..1668f7ecae 100644 --- a/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; import TopFilterItem from '../TopFilterItem'; const propTypes = { - filter: React.PropTypes.object, - tags: React.PropTypes.array, - clearFilterGroup: React.PropTypes.func + filter: PropTypes.object, + tags: PropTypes.array, + clearFilterGroup: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/topFilterBar/filterGroups/BudgetCategoryFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/BudgetCategoryFilterGroup.jsx index 0efe939552..9a2883e24f 100644 --- a/src/js/components/search/topFilterBar/filterGroups/BudgetCategoryFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/BudgetCategoryFilterGroup.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { toArray, indexOf, concat, difference } from 'lodash'; import { Set } from 'immutable'; @@ -13,8 +14,8 @@ import * as ObjectClasses from 'dataMapping/search/budgetCategory'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class BudgetCategoryFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/KeywordFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/KeywordFilterGroup.jsx index f013d5e346..afd14f972e 100644 --- a/src/js/components/search/topFilterBar/filterGroups/KeywordFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/KeywordFilterGroup.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class KeywordFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/LocationFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/LocationFilterGroup.jsx index 1439e87e67..cc1bdd8ef5 100644 --- a/src/js/components/search/topFilterBar/filterGroups/LocationFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/LocationFilterGroup.jsx @@ -4,15 +4,16 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { dropRight } from 'lodash'; import * as LocationFormatter from 'helpers/locationFormatter'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object, - toggle: React.PropTypes.string + filter: PropTypes.object, + redux: PropTypes.object, + toggle: PropTypes.string }; const scopeLabels = { diff --git a/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx index 38d4d51ea7..d8f8fa14f3 100644 --- a/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class RecipientFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/RecipientTypeFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/RecipientTypeFilterGroup.jsx index 875fa1f898..68aab00e15 100644 --- a/src/js/components/search/topFilterBar/filterGroups/RecipientTypeFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/RecipientTypeFilterGroup.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { indexOf, difference, concat } from 'lodash'; import { Set } from 'immutable'; @@ -13,8 +14,8 @@ import * as RecipientType from 'dataMapping/search/recipientType'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class RecipientTypeFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx index 5d571bb159..d3710e9223 100644 --- a/src/js/components/search/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/TimePeriodDRFilterGroup.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class TimePeriodDRFilterGroup extends React.Component { diff --git a/src/js/components/search/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx index 46b193554f..2ff4f8a952 100644 --- a/src/js/components/search/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/TimePeriodFYFilterGroup.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as FiscalYearHelper from 'helpers/fiscalYearHelper'; import BaseTopFilterGroup from './BaseTopFilterGroup'; const propTypes = { - filter: React.PropTypes.object, - redux: React.PropTypes.object + filter: PropTypes.object, + redux: PropTypes.object }; export default class TimePeriodFYFilterGroup extends React.Component { diff --git a/src/js/components/search/visualizations/geo/GeoVisualizationScopeButton.jsx b/src/js/components/search/visualizations/geo/GeoVisualizationScopeButton.jsx index f1387186d7..0ed6e68510 100644 --- a/src/js/components/search/visualizations/geo/GeoVisualizationScopeButton.jsx +++ b/src/js/components/search/visualizations/geo/GeoVisualizationScopeButton.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - active: React.PropTypes.bool, - value: React.PropTypes.string, - label: React.PropTypes.string, - changeScope: React.PropTypes.func + active: PropTypes.bool, + value: PropTypes.string, + label: PropTypes.string, + changeScope: PropTypes.func }; export default class GeoVisualizationScopeButton extends React.Component { diff --git a/src/js/components/search/visualizations/geo/GeoVisualizationSection.jsx b/src/js/components/search/visualizations/geo/GeoVisualizationSection.jsx index 42c43d323a..1afd3ea815 100644 --- a/src/js/components/search/visualizations/geo/GeoVisualizationSection.jsx +++ b/src/js/components/search/visualizations/geo/GeoVisualizationSection.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { indexOf } from 'lodash'; @@ -12,10 +13,10 @@ import MapWrapper from './MapWrapper'; import GeoVisualizationTooltip from './GeoVisualizationTooltip'; const propTypes = { - scope: React.PropTypes.string, - changeScope: React.PropTypes.func, - data: React.PropTypes.object, - total: React.PropTypes.number + scope: PropTypes.string, + changeScope: PropTypes.func, + data: PropTypes.object, + total: PropTypes.number }; export default class GeoVisualizationSection extends React.Component { diff --git a/src/js/components/search/visualizations/geo/GeoVisualizationTooltip.jsx b/src/js/components/search/visualizations/geo/GeoVisualizationTooltip.jsx index 967100b9cf..c400773017 100644 --- a/src/js/components/search/visualizations/geo/GeoVisualizationTooltip.jsx +++ b/src/js/components/search/visualizations/geo/GeoVisualizationTooltip.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import * as MapHelper from 'helpers/mapHelper'; const propTypes = { - state: React.PropTypes.string, - value: React.PropTypes.number, - y: React.PropTypes.number, - x: React.PropTypes.number, - visualization: React.PropTypes.object, - total: React.PropTypes.number + state: PropTypes.string, + value: PropTypes.number, + y: PropTypes.number, + x: PropTypes.number, + visualization: PropTypes.object, + total: PropTypes.number }; export default class GeoVisualizationTooltip extends React.Component { diff --git a/src/js/components/search/visualizations/geo/MapLegend.jsx b/src/js/components/search/visualizations/geo/MapLegend.jsx index 7acaccd9d4..6587557005 100644 --- a/src/js/components/search/visualizations/geo/MapLegend.jsx +++ b/src/js/components/search/visualizations/geo/MapLegend.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import * as MapHelper from 'helpers/mapHelper'; @@ -11,8 +12,8 @@ import * as MapHelper from 'helpers/mapHelper'; import MapLegendItem from './MapLegendItem'; const propTypes = { - segments: React.PropTypes.array, - units: React.PropTypes.object + segments: PropTypes.array, + units: PropTypes.object }; const defaultProps = { diff --git a/src/js/components/search/visualizations/geo/MapLegendItem.jsx b/src/js/components/search/visualizations/geo/MapLegendItem.jsx index 9c38f7a7d3..ace9d372ae 100644 --- a/src/js/components/search/visualizations/geo/MapLegendItem.jsx +++ b/src/js/components/search/visualizations/geo/MapLegendItem.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - color: React.PropTypes.string, - label: React.PropTypes.string + color: PropTypes.string, + label: PropTypes.string }; export default class MapLegendItem extends React.Component { diff --git a/src/js/components/search/visualizations/geo/MapWrapper.jsx b/src/js/components/search/visualizations/geo/MapWrapper.jsx index 682a0289ca..4ca635ef83 100644 --- a/src/js/components/search/visualizations/geo/MapWrapper.jsx +++ b/src/js/components/search/visualizations/geo/MapWrapper.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Q from 'q'; import * as MapHelper from 'helpers/mapHelper'; @@ -12,13 +13,13 @@ import MapBox from './map/MapBox'; import MapLegend from './MapLegend'; const propTypes = { - data: React.PropTypes.object, - renderHash: React.PropTypes.string, - showHover: React.PropTypes.bool, - selectedItem: React.PropTypes.object, - showTooltip: React.PropTypes.func, - hideTooltip: React.PropTypes.func, - tooltip: React.PropTypes.func + data: PropTypes.object, + renderHash: PropTypes.string, + showHover: PropTypes.bool, + selectedItem: PropTypes.object, + showTooltip: PropTypes.func, + hideTooltip: PropTypes.func, + tooltip: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/visualizations/geo/map/MapBox.jsx b/src/js/components/search/visualizations/geo/map/MapBox.jsx index 7767c49049..424168a09c 100644 --- a/src/js/components/search/visualizations/geo/map/MapBox.jsx +++ b/src/js/components/search/visualizations/geo/map/MapBox.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import MapboxGL from 'mapbox-gl/dist/mapbox-gl'; import { throttle } from 'lodash'; import * as Icons from 'components/sharedComponents/icons/Icons'; @@ -11,10 +12,10 @@ import * as Icons from 'components/sharedComponents/icons/Icons'; import kGlobalConstants from 'GlobalConstants'; const propTypes = { - loadedMap: React.PropTypes.func, - unloadedMap: React.PropTypes.func, - showTooltip: React.PropTypes.func, - hideTooltip: React.PropTypes.func + loadedMap: PropTypes.func, + unloadedMap: PropTypes.func, + showTooltip: PropTypes.func, + hideTooltip: PropTypes.func }; // Define map movement increment diff --git a/src/js/components/search/visualizations/rank/RankVisualization.jsx b/src/js/components/search/visualizations/rank/RankVisualization.jsx index 53a14f8e21..32428a644e 100644 --- a/src/js/components/search/visualizations/rank/RankVisualization.jsx +++ b/src/js/components/search/visualizations/rank/RankVisualization.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import HorizontalChart from './chart/HorizontalChart'; import RankVisualizationTooltip from './RankVisualizationTooltip'; @@ -22,11 +23,11 @@ const defaultProps = { }; const propTypes = { - dataSeries: React.PropTypes.array, - descriptions: React.PropTypes.array, - loading: React.PropTypes.bool, - meta: React.PropTypes.object, - disableTooltip: React.PropTypes.bool + dataSeries: PropTypes.array, + descriptions: PropTypes.array, + loading: PropTypes.bool, + meta: PropTypes.object, + disableTooltip: PropTypes.bool }; export default class RankVisualization extends React.Component { diff --git a/src/js/components/search/visualizations/rank/RankVisualizationChartMessage.jsx b/src/js/components/search/visualizations/rank/RankVisualizationChartMessage.jsx index 862dfb96fd..dafeb8b64a 100644 --- a/src/js/components/search/visualizations/rank/RankVisualizationChartMessage.jsx +++ b/src/js/components/search/visualizations/rank/RankVisualizationChartMessage.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - message: React.PropTypes.string + message: PropTypes.string }; export default class RankVisualizationChartMessage extends React.Component { diff --git a/src/js/components/search/visualizations/rank/RankVisualizationScopeButton.jsx b/src/js/components/search/visualizations/rank/RankVisualizationScopeButton.jsx index 7f7ac7e0f8..f6f998c72f 100644 --- a/src/js/components/search/visualizations/rank/RankVisualizationScopeButton.jsx +++ b/src/js/components/search/visualizations/rank/RankVisualizationScopeButton.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - active: React.PropTypes.bool, - value: React.PropTypes.string, - label: React.PropTypes.string, - disabled: React.PropTypes.bool, - changeScope: React.PropTypes.func + active: PropTypes.bool, + value: PropTypes.string, + label: PropTypes.string, + disabled: PropTypes.bool, + changeScope: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/search/visualizations/rank/RankVisualizationTitle.jsx b/src/js/components/search/visualizations/rank/RankVisualizationTitle.jsx index a96fef3a82..68d9a7b490 100644 --- a/src/js/components/search/visualizations/rank/RankVisualizationTitle.jsx +++ b/src/js/components/search/visualizations/rank/RankVisualizationTitle.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { find } from 'lodash'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - fieldTypes: React.PropTypes.array, - changeSpendingBy: React.PropTypes.func, - currentSpendingBy: React.PropTypes.string + fieldTypes: PropTypes.array, + changeSpendingBy: PropTypes.func, + currentSpendingBy: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/search/visualizations/rank/RankVisualizationTooltip.jsx b/src/js/components/search/visualizations/rank/RankVisualizationTooltip.jsx index b011bdf789..7e9a6ab9cc 100644 --- a/src/js/components/search/visualizations/rank/RankVisualizationTooltip.jsx +++ b/src/js/components/search/visualizations/rank/RankVisualizationTooltip.jsx @@ -4,15 +4,16 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - label: React.PropTypes.string, - value: React.PropTypes.number, - y: React.PropTypes.number, - x: React.PropTypes.number, - visualization: React.PropTypes.object + label: PropTypes.string, + value: PropTypes.number, + y: PropTypes.number, + x: PropTypes.number, + visualization: PropTypes.object }; export default class RankVisualizationTooltip extends React.Component { diff --git a/src/js/components/search/visualizations/rank/chart/ChartBar.jsx b/src/js/components/search/visualizations/rank/chart/ChartBar.jsx index 6459c795e5..2341d4da16 100644 --- a/src/js/components/search/visualizations/rank/chart/ChartBar.jsx +++ b/src/js/components/search/visualizations/rank/chart/ChartBar.jsx @@ -4,20 +4,21 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - labelWidth: React.PropTypes.number, - maxWidth: React.PropTypes.number, - width: React.PropTypes.number, - height: React.PropTypes.number, - start: React.PropTypes.number, - index: React.PropTypes.number, - label: React.PropTypes.string, - value: React.PropTypes.number, - description: React.PropTypes.string, - disableTooltip: React.PropTypes.bool, - selectItem: React.PropTypes.func, - deselectItem: React.PropTypes.func + labelWidth: PropTypes.number, + maxWidth: PropTypes.number, + width: PropTypes.number, + height: PropTypes.number, + start: PropTypes.number, + index: PropTypes.number, + label: PropTypes.string, + value: PropTypes.number, + description: PropTypes.string, + disableTooltip: PropTypes.bool, + selectItem: PropTypes.func, + deselectItem: PropTypes.func }; export default class ChartBar extends React.Component { diff --git a/src/js/components/search/visualizations/rank/chart/ChartGroup.jsx b/src/js/components/search/visualizations/rank/chart/ChartGroup.jsx index f012060767..aeafd22606 100644 --- a/src/js/components/search/visualizations/rank/chart/ChartGroup.jsx +++ b/src/js/components/search/visualizations/rank/chart/ChartGroup.jsx @@ -4,17 +4,18 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { truncate } from 'lodash'; const propTypes = { - label: React.PropTypes.string, - labelWidth: React.PropTypes.number, - width: React.PropTypes.number, - height: React.PropTypes.number, - index: React.PropTypes.number, - linkID: React.PropTypes.string, - urlRoot: React.PropTypes.string, - clickedGroup: React.PropTypes.func + label: PropTypes.string, + labelWidth: PropTypes.number, + width: PropTypes.number, + height: PropTypes.number, + index: PropTypes.number, + linkID: PropTypes.string, + urlRoot: PropTypes.string, + clickedGroup: PropTypes.func }; export default class ChartGroup extends React.Component { diff --git a/src/js/components/search/visualizations/rank/chart/HorizontalChart.jsx b/src/js/components/search/visualizations/rank/chart/HorizontalChart.jsx index 199716a756..3b67428268 100644 --- a/src/js/components/search/visualizations/rank/chart/HorizontalChart.jsx +++ b/src/js/components/search/visualizations/rank/chart/HorizontalChart.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { min, max } from 'lodash'; import { scaleLinear } from 'd3-scale'; @@ -13,20 +14,20 @@ import ChartGroup from './ChartGroup'; import ChartBar from './ChartBar'; const propTypes = { - width: React.PropTypes.number, - height: React.PropTypes.number, - dataSeries: React.PropTypes.array, - labelSeries: React.PropTypes.array, - linkSeries: React.PropTypes.array, - descriptions: React.PropTypes.array, - labelWidth: React.PropTypes.number, - padding: React.PropTypes.object, - itemHeight: React.PropTypes.number, - disableTooltip: React.PropTypes.bool, - selectItem: React.PropTypes.func, - deselectItem: React.PropTypes.func, - clickedGroup: React.PropTypes.func, - urlRoot: React.PropTypes.string + width: PropTypes.number, + height: PropTypes.number, + dataSeries: PropTypes.array, + labelSeries: PropTypes.array, + linkSeries: PropTypes.array, + descriptions: PropTypes.array, + labelWidth: PropTypes.number, + padding: PropTypes.object, + itemHeight: PropTypes.number, + disableTooltip: PropTypes.bool, + selectItem: PropTypes.func, + deselectItem: PropTypes.func, + clickedGroup: PropTypes.func, + urlRoot: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/search/visualizations/rank/chart/HorizontalXAxis.jsx b/src/js/components/search/visualizations/rank/chart/HorizontalXAxis.jsx index f92db0481f..e834e48e80 100644 --- a/src/js/components/search/visualizations/rank/chart/HorizontalXAxis.jsx +++ b/src/js/components/search/visualizations/rank/chart/HorizontalXAxis.jsx @@ -4,16 +4,17 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import HorizontalXLabel from './HorizontalXLabel'; const propTypes = { - range: React.PropTypes.array, - x: React.PropTypes.number, - y: React.PropTypes.number, - width: React.PropTypes.number + range: PropTypes.array, + x: PropTypes.number, + y: PropTypes.number, + width: PropTypes.number }; export default class HorizontalXAxis extends React.Component { diff --git a/src/js/components/search/visualizations/rank/chart/HorizontalXLabel.jsx b/src/js/components/search/visualizations/rank/chart/HorizontalXLabel.jsx index f8a4c3b066..76ac0e866e 100644 --- a/src/js/components/search/visualizations/rank/chart/HorizontalXLabel.jsx +++ b/src/js/components/search/visualizations/rank/chart/HorizontalXLabel.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - height: React.PropTypes.number, - label: React.PropTypes.string, - alignment: React.PropTypes.string + x: PropTypes.number, + y: PropTypes.number, + height: PropTypes.number, + label: PropTypes.string, + alignment: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/search/visualizations/rank/chart/HorizontalYAxis.jsx b/src/js/components/search/visualizations/rank/chart/HorizontalYAxis.jsx index 8f70218858..afcce6e507 100644 --- a/src/js/components/search/visualizations/rank/chart/HorizontalYAxis.jsx +++ b/src/js/components/search/visualizations/rank/chart/HorizontalYAxis.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - xScale: React.PropTypes.func, - x: React.PropTypes.number, - y: React.PropTypes.number, - height: React.PropTypes.number + xScale: PropTypes.func, + x: PropTypes.number, + y: PropTypes.number, + height: PropTypes.number }; export default class HorizontalYAxis extends React.Component { diff --git a/src/js/components/search/visualizations/rank/sections/RankVisualizationSection.jsx b/src/js/components/search/visualizations/rank/sections/RankVisualizationSection.jsx index a7e1e47d4d..870fb49049 100644 --- a/src/js/components/search/visualizations/rank/sections/RankVisualizationSection.jsx +++ b/src/js/components/search/visualizations/rank/sections/RankVisualizationSection.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle, min } from 'lodash'; import * as Icons from 'components/sharedComponents/icons/Icons'; @@ -11,12 +12,12 @@ import * as Icons from 'components/sharedComponents/icons/Icons'; import RankVisualization from '../RankVisualization'; const propTypes = { - nextPage: React.PropTypes.func, - previousPage: React.PropTypes.func, - loading: React.PropTypes.bool, - hasNextPage: React.PropTypes.bool, - hasPreviousPage: React.PropTypes.bool, - children: React.PropTypes.node + nextPage: PropTypes.func, + previousPage: PropTypes.func, + loading: PropTypes.bool, + hasNextPage: PropTypes.bool, + hasPreviousPage: PropTypes.bool, + children: PropTypes.node }; export default class RankVisualizationSection extends React.Component { diff --git a/src/js/components/search/visualizations/rank/sections/SpendingByAgencySection.jsx b/src/js/components/search/visualizations/rank/sections/SpendingByAgencySection.jsx index 2dafca2b6e..a62e0f2944 100644 --- a/src/js/components/search/visualizations/rank/sections/SpendingByAgencySection.jsx +++ b/src/js/components/search/visualizations/rank/sections/SpendingByAgencySection.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; import RankVisualizationScopeButton from '../RankVisualizationScopeButton'; @@ -11,10 +12,10 @@ import RankVisualizationScopeButton from '../RankVisualizationScopeButton'; import RankVisualizationSection from './RankVisualizationSection'; const propTypes = { - agencyScope: React.PropTypes.string, - changeScope: React.PropTypes.func, - agencyType: React.PropTypes.string, - hideSuboptionBar: React.PropTypes.string + agencyScope: PropTypes.string, + changeScope: PropTypes.func, + agencyType: PropTypes.string, + hideSuboptionBar: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/search/visualizations/rank/sections/SpendingByCategorySection.jsx b/src/js/components/search/visualizations/rank/sections/SpendingByCategorySection.jsx index 78ecf8c939..99cd63b4e2 100644 --- a/src/js/components/search/visualizations/rank/sections/SpendingByCategorySection.jsx +++ b/src/js/components/search/visualizations/rank/sections/SpendingByCategorySection.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import RankVisualizationScopeButton from '../RankVisualizationScopeButton'; import RankVisualizationSection from './RankVisualizationSection'; const propTypes = { - scope: React.PropTypes.string, - changeScope: React.PropTypes.func + scope: PropTypes.string, + changeScope: PropTypes.func }; export default class SpendingByCategorySection extends React.Component { diff --git a/src/js/components/search/visualizations/rank/sections/SpendingByIndustryCodeSection.jsx b/src/js/components/search/visualizations/rank/sections/SpendingByIndustryCodeSection.jsx index 1d8d08040c..b75ca5ac87 100644 --- a/src/js/components/search/visualizations/rank/sections/SpendingByIndustryCodeSection.jsx +++ b/src/js/components/search/visualizations/rank/sections/SpendingByIndustryCodeSection.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import RankVisualizationScopeButton from '../RankVisualizationScopeButton'; import RankVisualizationSection from './RankVisualizationSection'; const propTypes = { - scope: React.PropTypes.string, - changeScope: React.PropTypes.func + scope: PropTypes.string, + changeScope: PropTypes.func }; export default class SpendingByIndustryCodeSection extends React.Component { diff --git a/src/js/components/search/visualizations/rank/sections/SpendingByRecipientSection.jsx b/src/js/components/search/visualizations/rank/sections/SpendingByRecipientSection.jsx index c40431a44c..f0a1d8e23e 100644 --- a/src/js/components/search/visualizations/rank/sections/SpendingByRecipientSection.jsx +++ b/src/js/components/search/visualizations/rank/sections/SpendingByRecipientSection.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; import RankVisualizationScopeButton from '../RankVisualizationScopeButton'; import RankVisualizationSection from './RankVisualizationSection'; const propTypes = { - scope: React.PropTypes.string, - changeScope: React.PropTypes.func + scope: PropTypes.string, + changeScope: PropTypes.func }; export default class SpendingByRecipientSection extends React.Component { diff --git a/src/js/components/search/visualizations/time/TimeVisualization.jsx b/src/js/components/search/visualizations/time/TimeVisualization.jsx index cb840740ff..56505d39b4 100644 --- a/src/js/components/search/visualizations/time/TimeVisualization.jsx +++ b/src/js/components/search/visualizations/time/TimeVisualization.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BarChart from './chart/BarChart'; import Tooltip from './TimeVisualizationTooltip'; @@ -36,12 +37,12 @@ const defaultProps = { /* eslint-disable react/no-unused-prop-types */ // allow unused prop types. they are passed to child components, but documented here const propTypes = { - width: React.PropTypes.number, - height: React.PropTypes.number, - groups: React.PropTypes.array, - xSeries: React.PropTypes.array, - ySeries: React.PropTypes.array, - loading: React.PropTypes.bool + width: PropTypes.number, + height: PropTypes.number, + groups: PropTypes.array, + xSeries: PropTypes.array, + ySeries: PropTypes.array, + loading: PropTypes.bool }; /* eslint-enable react/no-unused-prop-types */ diff --git a/src/js/components/search/visualizations/time/TimeVisualizationChartMessage.jsx b/src/js/components/search/visualizations/time/TimeVisualizationChartMessage.jsx index 93ce7468ed..600aceba04 100644 --- a/src/js/components/search/visualizations/time/TimeVisualizationChartMessage.jsx +++ b/src/js/components/search/visualizations/time/TimeVisualizationChartMessage.jsx @@ -4,9 +4,10 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - message: React.PropTypes.string + message: PropTypes.string }; export default class TimeVisualizationChartMessage extends React.Component { diff --git a/src/js/components/search/visualizations/time/TimeVisualizationPeriodButton.jsx b/src/js/components/search/visualizations/time/TimeVisualizationPeriodButton.jsx index fc622453f8..0a5da7b9bc 100644 --- a/src/js/components/search/visualizations/time/TimeVisualizationPeriodButton.jsx +++ b/src/js/components/search/visualizations/time/TimeVisualizationPeriodButton.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - active: React.PropTypes.bool, - value: React.PropTypes.string, - label: React.PropTypes.string, - changePeriod: React.PropTypes.func + active: PropTypes.bool, + value: PropTypes.string, + label: PropTypes.string, + changePeriod: PropTypes.func }; export default class TimeVisualizationPeriodButton extends React.Component { diff --git a/src/js/components/search/visualizations/time/TimeVisualizationSection.jsx b/src/js/components/search/visualizations/time/TimeVisualizationSection.jsx index 1d32f081eb..cc2b2158ce 100644 --- a/src/js/components/search/visualizations/time/TimeVisualizationSection.jsx +++ b/src/js/components/search/visualizations/time/TimeVisualizationSection.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; @@ -11,7 +12,7 @@ import TimeVisualization from './TimeVisualization'; import TimeVisualizationPeriodButton from './TimeVisualizationPeriodButton'; const propTypes = { - data: React.PropTypes.object + data: PropTypes.object }; export default class TimeVisualizationSection extends React.Component { diff --git a/src/js/components/search/visualizations/time/TimeVisualizationTooltip.jsx b/src/js/components/search/visualizations/time/TimeVisualizationTooltip.jsx index 718bd1ec82..81ff535b1e 100644 --- a/src/js/components/search/visualizations/time/TimeVisualizationTooltip.jsx +++ b/src/js/components/search/visualizations/time/TimeVisualizationTooltip.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; const propTypes = { - y: React.PropTypes.number, - x: React.PropTypes.number, - data: React.PropTypes.object + y: PropTypes.number, + x: PropTypes.number, + data: PropTypes.object }; export default class TimeVisualizationTooltip extends React.Component { diff --git a/src/js/components/search/visualizations/time/chart/BarChart.jsx b/src/js/components/search/visualizations/time/chart/BarChart.jsx index a2a9e85a98..72f3ec8b9a 100644 --- a/src/js/components/search/visualizations/time/chart/BarChart.jsx +++ b/src/js/components/search/visualizations/time/chart/BarChart.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { scaleBand, scaleLinear } from 'd3-scale'; import { isEqual, flattenDeep, min, max, mean, forEach, sum } from 'lodash'; @@ -17,15 +18,15 @@ import BarChartLegend from './BarChartLegend'; /* eslint-disable react/no-unused-prop-types */ // we're catching the props before they're fully set, so eslint thinks these props are unused const propTypes = { - groups: React.PropTypes.array, - width: React.PropTypes.number, - height: React.PropTypes.number, - xSeries: React.PropTypes.array, - ySeries: React.PropTypes.array, - showTooltip: React.PropTypes.func, - enableHighlight: React.PropTypes.bool, - padding: React.PropTypes.object, - legend: React.PropTypes.array + groups: PropTypes.array, + width: PropTypes.number, + height: PropTypes.number, + xSeries: PropTypes.array, + ySeries: PropTypes.array, + showTooltip: PropTypes.func, + enableHighlight: PropTypes.bool, + padding: PropTypes.object, + legend: PropTypes.array }; /* eslint-enable react/no-unused-prop-types */ diff --git a/src/js/components/search/visualizations/time/chart/BarChartLegend.jsx b/src/js/components/search/visualizations/time/chart/BarChartLegend.jsx index b675a69989..73e55e3539 100644 --- a/src/js/components/search/visualizations/time/chart/BarChartLegend.jsx +++ b/src/js/components/search/visualizations/time/chart/BarChartLegend.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import BarChartLegendItem from './BarChartLegendItem'; const propTypes = { - legend: React.PropTypes.arrayOf(React.PropTypes.object) + legend: PropTypes.arrayOf(PropTypes.object) }; export default class BarChartLegend extends React.Component { diff --git a/src/js/components/search/visualizations/time/chart/BarChartLegendItem.jsx b/src/js/components/search/visualizations/time/chart/BarChartLegendItem.jsx index f4b281e0ce..7ddebb3b96 100644 --- a/src/js/components/search/visualizations/time/chart/BarChartLegendItem.jsx +++ b/src/js/components/search/visualizations/time/chart/BarChartLegendItem.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - color: React.PropTypes.string, - label: React.PropTypes.string, - offset: React.PropTypes.number + color: PropTypes.string, + label: PropTypes.string, + offset: PropTypes.number }; export default class BarChartLegendItem extends React.Component { diff --git a/src/js/components/search/visualizations/time/chart/BarItem.jsx b/src/js/components/search/visualizations/time/chart/BarItem.jsx index 2c40505374..2e58fda0e4 100644 --- a/src/js/components/search/visualizations/time/chart/BarItem.jsx +++ b/src/js/components/search/visualizations/time/chart/BarItem.jsx @@ -4,25 +4,26 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const defaultProps = { active: false }; const propTypes = { - identifier: React.PropTypes.string, - dataY: React.PropTypes.number, - dataX: React.PropTypes.string, - graphHeight: React.PropTypes.number, - height: React.PropTypes.number, - width: React.PropTypes.number, - x: React.PropTypes.number, - y: React.PropTypes.number, - color: React.PropTypes.string, - description: React.PropTypes.string, - selectBar: React.PropTypes.func, - deselectBar: React.PropTypes.func, - deregisterBar: React.PropTypes.func + identifier: PropTypes.string, + dataY: PropTypes.number, + dataX: PropTypes.string, + graphHeight: PropTypes.number, + height: PropTypes.number, + width: PropTypes.number, + x: PropTypes.number, + y: PropTypes.number, + color: PropTypes.string, + description: PropTypes.string, + selectBar: PropTypes.func, + deselectBar: PropTypes.func, + deregisterBar: PropTypes.func }; export default class BarItem extends React.Component { diff --git a/src/js/components/search/visualizations/time/chart/BarXAxis.jsx b/src/js/components/search/visualizations/time/chart/BarXAxis.jsx index 9250fb142f..8ba502d70a 100644 --- a/src/js/components/search/visualizations/time/chart/BarXAxis.jsx +++ b/src/js/components/search/visualizations/time/chart/BarXAxis.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isEqual } from 'lodash'; import BarXAxisItem from './BarXAxisItem'; @@ -19,10 +20,10 @@ const defaultProps = { }; const propTypes = { - top: React.PropTypes.number.isRequired, - width: React.PropTypes.number.isRequired, - padding: React.PropTypes.object, - axisPos: React.PropTypes.number + top: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + padding: PropTypes.object, + axisPos: PropTypes.number }; export default class BarXAxis extends React.Component { diff --git a/src/js/components/search/visualizations/time/chart/BarXAxisItem.jsx b/src/js/components/search/visualizations/time/chart/BarXAxisItem.jsx index bb30db68bc..00e1d323e4 100644 --- a/src/js/components/search/visualizations/time/chart/BarXAxisItem.jsx +++ b/src/js/components/search/visualizations/time/chart/BarXAxisItem.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - label: React.PropTypes.string + x: PropTypes.number, + y: PropTypes.number, + label: PropTypes.string }; export default class BarXAxisItem extends React.Component { diff --git a/src/js/components/search/visualizations/time/chart/BarYAxis.jsx b/src/js/components/search/visualizations/time/chart/BarYAxis.jsx index 3f56985dbe..aed1fa101d 100644 --- a/src/js/components/search/visualizations/time/chart/BarYAxis.jsx +++ b/src/js/components/search/visualizations/time/chart/BarYAxis.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import { isEqual } from 'lodash'; @@ -12,11 +13,11 @@ import BarYAxisItem from './BarYAxisItem'; /* eslint-disable react/no-unused-prop-types */ // we're catching the props before they're fully set, so eslint thinks these props are unused const propTypes = { - width: React.PropTypes.number.isRequired, - height: React.PropTypes.number.isRequired, - padding: React.PropTypes.object, - scale: React.PropTypes.func, - average: React.PropTypes.number + width: PropTypes.number.isRequired, + height: PropTypes.number.isRequired, + padding: PropTypes.object, + scale: PropTypes.func, + average: PropTypes.number }; /* eslint-enable react/no-unused-prop-types */ diff --git a/src/js/components/search/visualizations/time/chart/BarYAxisItem.jsx b/src/js/components/search/visualizations/time/chart/BarYAxisItem.jsx index 448e5165b8..142cc5f515 100644 --- a/src/js/components/search/visualizations/time/chart/BarYAxisItem.jsx +++ b/src/js/components/search/visualizations/time/chart/BarYAxisItem.jsx @@ -4,13 +4,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - x: React.PropTypes.number, - y: React.PropTypes.number, - label: React.PropTypes.string, - lineStart: React.PropTypes.number, - lineEnd: React.PropTypes.number + x: PropTypes.number, + y: PropTypes.number, + label: PropTypes.string, + lineStart: PropTypes.number, + lineEnd: PropTypes.number }; export default class BarYAxisItem extends React.Component { diff --git a/src/js/components/sharedComponents/DatePicker.jsx b/src/js/components/sharedComponents/DatePicker.jsx index 68acf02c69..facdd044b4 100644 --- a/src/js/components/sharedComponents/DatePicker.jsx +++ b/src/js/components/sharedComponents/DatePicker.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import DayPicker, { DateUtils } from 'react-day-picker'; import moment from 'moment'; import * as Icons from './icons/Icons'; @@ -14,14 +15,14 @@ const defaultProps = { }; const propTypes = { - value: React.PropTypes.object, - type: React.PropTypes.string, - onDateChange: React.PropTypes.func, - showError: React.PropTypes.func, - hideError: React.PropTypes.func, - opposite: React.PropTypes.object, - tabIndex: React.PropTypes.number, - title: React.PropTypes.string + value: PropTypes.object, + type: PropTypes.string, + onDateChange: PropTypes.func, + showError: PropTypes.func, + hideError: PropTypes.func, + opposite: PropTypes.object, + tabIndex: PropTypes.number, + title: PropTypes.string }; export default class DatePicker extends React.Component { diff --git a/src/js/components/sharedComponents/Error.jsx b/src/js/components/sharedComponents/Error.jsx index 8555014693..bbfdb838bd 100644 --- a/src/js/components/sharedComponents/Error.jsx +++ b/src/js/components/sharedComponents/Error.jsx @@ -4,10 +4,11 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - title: React.PropTypes.string, - message: React.PropTypes.string + title: PropTypes.string, + message: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/sharedComponents/FloatingGlossaryButton.jsx b/src/js/components/sharedComponents/FloatingGlossaryButton.jsx index fdf163e06d..2c7f7658ad 100644 --- a/src/js/components/sharedComponents/FloatingGlossaryButton.jsx +++ b/src/js/components/sharedComponents/FloatingGlossaryButton.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Glossary } from './icons/Icons'; const propTypes = { - toggleGlossary: React.PropTypes.func + toggleGlossary: PropTypes.func }; export default class FloatingGlossaryButton extends React.Component { diff --git a/src/js/components/sharedComponents/IBTable/components/HeaderCell.jsx b/src/js/components/sharedComponents/IBTable/components/HeaderCell.jsx index 1f75092096..55ae577299 100644 --- a/src/js/components/sharedComponents/IBTable/components/HeaderCell.jsx +++ b/src/js/components/sharedComponents/IBTable/components/HeaderCell.jsx @@ -4,11 +4,12 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - height: React.PropTypes.number, - width: React.PropTypes.number, - header: React.PropTypes.node + height: PropTypes.number, + width: PropTypes.number, + header: PropTypes.node }; export default class HeaderCell extends React.Component { diff --git a/src/js/components/sharedComponents/IBTable/components/HeaderRow.jsx b/src/js/components/sharedComponents/IBTable/components/HeaderRow.jsx index acbb82e8f5..d8511f9364 100644 --- a/src/js/components/sharedComponents/IBTable/components/HeaderRow.jsx +++ b/src/js/components/sharedComponents/IBTable/components/HeaderRow.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { min } from 'lodash'; import HeaderCell from './HeaderCell'; const propTypes = { - headerHeight: React.PropTypes.number, - maxWidth: React.PropTypes.number, - width: React.PropTypes.number, - columns: React.PropTypes.array + headerHeight: PropTypes.number, + maxWidth: PropTypes.number, + width: PropTypes.number, + columns: PropTypes.array }; export default class HeaderRow extends React.Component { diff --git a/src/js/components/sharedComponents/IBTable/components/Table.jsx b/src/js/components/sharedComponents/IBTable/components/Table.jsx index ddc266498f..70b98ddb76 100644 --- a/src/js/components/sharedComponents/IBTable/components/Table.jsx +++ b/src/js/components/sharedComponents/IBTable/components/Table.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import HeaderRow from './HeaderRow'; import TableBody from './TableBody'; @@ -13,8 +14,8 @@ const defaultProps = { }; const propTypes = { - resetHash: React.PropTypes.string, - maxWidth: React.PropTypes.number.isRequired + resetHash: PropTypes.string, + maxWidth: PropTypes.number.isRequired }; export default class Table extends React.Component { diff --git a/src/js/components/sharedComponents/IBTable/components/TableBody.jsx b/src/js/components/sharedComponents/IBTable/components/TableBody.jsx index d6efd1bd38..76b7bda0f1 100644 --- a/src/js/components/sharedComponents/IBTable/components/TableBody.jsx +++ b/src/js/components/sharedComponents/IBTable/components/TableBody.jsx @@ -4,19 +4,20 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { max, min } from 'lodash'; import TableRow from './TableRow'; const propTypes = { - rowHeight: React.PropTypes.number.isRequired, - rowCount: React.PropTypes.number.isRequired, - maxWidth: React.PropTypes.number.isRequired, - maxHeight: React.PropTypes.number.isRequired, - width: React.PropTypes.number.isRequired, - columns: React.PropTypes.array.isRequired, - dataHash: React.PropTypes.string, - onScrollEnd: React.PropTypes.func, - syncScrollPosition: React.PropTypes.func + rowHeight: PropTypes.number.isRequired, + rowCount: PropTypes.number.isRequired, + maxWidth: PropTypes.number.isRequired, + maxHeight: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + columns: PropTypes.array.isRequired, + dataHash: PropTypes.string, + onScrollEnd: PropTypes.func, + syncScrollPosition: PropTypes.func }; export default class TableBody extends React.Component { diff --git a/src/js/components/sharedComponents/IBTable/components/TableCell.jsx b/src/js/components/sharedComponents/IBTable/components/TableCell.jsx index 37f8d21f3f..26c8267582 100644 --- a/src/js/components/sharedComponents/IBTable/components/TableCell.jsx +++ b/src/js/components/sharedComponents/IBTable/components/TableCell.jsx @@ -4,13 +4,14 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - height: React.PropTypes.number, - width: React.PropTypes.number, - left: React.PropTypes.number, - rowIndex: React.PropTypes.number, - column: React.PropTypes.object + height: PropTypes.number, + width: PropTypes.number, + left: PropTypes.number, + rowIndex: PropTypes.number, + column: PropTypes.object }; export default class TableCell extends React.Component { diff --git a/src/js/components/sharedComponents/IBTable/components/TableRow.jsx b/src/js/components/sharedComponents/IBTable/components/TableRow.jsx index f8e3fefb44..84cc2b05b5 100644 --- a/src/js/components/sharedComponents/IBTable/components/TableRow.jsx +++ b/src/js/components/sharedComponents/IBTable/components/TableRow.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import TableCell from './TableCell'; const propTypes = { - visibleColumns: React.PropTypes.array.isRequired, - visibleCoords: React.PropTypes.string.isRequired, - dataHash: React.PropTypes.string, - rowHeight: React.PropTypes.number.isRequired, - rowIndex: React.PropTypes.number.isRequired + visibleColumns: PropTypes.array.isRequired, + visibleCoords: PropTypes.string.isRequired, + dataHash: PropTypes.string, + rowHeight: PropTypes.number.isRequired, + rowIndex: PropTypes.number.isRequired }; export default class TableRow extends React.PureComponent { diff --git a/src/js/components/sharedComponents/ScrollTo.jsx b/src/js/components/sharedComponents/ScrollTo.jsx index 75e3c4b30d..6d852c577c 100644 --- a/src/js/components/sharedComponents/ScrollTo.jsx +++ b/src/js/components/sharedComponents/ScrollTo.jsx @@ -4,15 +4,16 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import $ from 'jquery'; const propTypes = { - code: React.PropTypes.string.isRequired, - icon: React.PropTypes.element.isRequired, - label: React.PropTypes.string.isRequired, - role: React.PropTypes.string.isRequired, - className: React.PropTypes.string.isRequired, - accessibleLabel: React.PropTypes.string.isRequired + code: PropTypes.string.isRequired, + icon: PropTypes.element.isRequired, + label: PropTypes.string.isRequired, + role: PropTypes.string.isRequired, + className: PropTypes.string.isRequired, + accessibleLabel: PropTypes.string.isRequired }; export default class ScrollTo extends React.Component { diff --git a/src/js/components/sharedComponents/ToggleButton.jsx b/src/js/components/sharedComponents/ToggleButton.jsx index 4c30df5011..b409638472 100644 --- a/src/js/components/sharedComponents/ToggleButton.jsx +++ b/src/js/components/sharedComponents/ToggleButton.jsx @@ -4,12 +4,13 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - active: React.PropTypes.bool, - pressedToggle: React.PropTypes.func, - label: React.PropTypes.string, - prefix: React.PropTypes.string + active: PropTypes.bool, + pressedToggle: PropTypes.func, + label: PropTypes.string, + prefix: PropTypes.string }; export default class ToggleButton extends React.Component { diff --git a/src/js/components/sharedComponents/autocomplete/Autocomplete.jsx b/src/js/components/sharedComponents/autocomplete/Autocomplete.jsx index 099858034f..b6b4c252b2 100644 --- a/src/js/components/sharedComponents/autocomplete/Autocomplete.jsx +++ b/src/js/components/sharedComponents/autocomplete/Autocomplete.jsx @@ -3,24 +3,25 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isEqual, find } from 'lodash'; import Warning from './Warning'; import SuggestionHolder from './SuggestionHolder'; const propTypes = { - handleTextInput: React.PropTypes.func.isRequired, - onSelect: React.PropTypes.func.isRequired, - clearAutocompleteSuggestions: React.PropTypes.func.isRequired, - values: React.PropTypes.array, - placeholder: React.PropTypes.string, - errorHeader: React.PropTypes.string, - errorMessage: React.PropTypes.string, - tabIndex: React.PropTypes.number, - isRequired: React.PropTypes.bool, - maxSuggestions: React.PropTypes.number, - label: React.PropTypes.string, - noResults: React.PropTypes.bool + handleTextInput: PropTypes.func.isRequired, + onSelect: PropTypes.func.isRequired, + clearAutocompleteSuggestions: PropTypes.func.isRequired, + values: PropTypes.array, + placeholder: PropTypes.string, + errorHeader: PropTypes.string, + errorMessage: PropTypes.string, + tabIndex: PropTypes.number, + isRequired: PropTypes.bool, + maxSuggestions: PropTypes.number, + label: PropTypes.string, + noResults: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/sharedComponents/autocomplete/Suggestion.jsx b/src/js/components/sharedComponents/autocomplete/Suggestion.jsx index 68ef8b5ad5..84160c95ec 100644 --- a/src/js/components/sharedComponents/autocomplete/Suggestion.jsx +++ b/src/js/components/sharedComponents/autocomplete/Suggestion.jsx @@ -3,13 +3,14 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - title: React.PropTypes.string, - subtitle: React.PropTypes.string, - data: React.PropTypes.object, - selected: React.PropTypes.bool, - select: React.PropTypes.func + title: PropTypes.string, + subtitle: PropTypes.string, + data: PropTypes.object, + selected: PropTypes.bool, + select: PropTypes.func }; const defaultProps = { diff --git a/src/js/components/sharedComponents/autocomplete/SuggestionHolder.jsx b/src/js/components/sharedComponents/autocomplete/SuggestionHolder.jsx index 8a1677289f..a46ec600a4 100644 --- a/src/js/components/sharedComponents/autocomplete/SuggestionHolder.jsx +++ b/src/js/components/sharedComponents/autocomplete/SuggestionHolder.jsx @@ -3,14 +3,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Suggestion from './Suggestion'; const propTypes = { - select: React.PropTypes.func, - suggestions: React.PropTypes.array, - selectedIndex: React.PropTypes.number, - maxSuggestions: React.PropTypes.number, - shown: React.PropTypes.string + select: PropTypes.func, + suggestions: PropTypes.array, + selectedIndex: PropTypes.number, + maxSuggestions: PropTypes.number, + shown: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/sharedComponents/autocomplete/Warning.jsx b/src/js/components/sharedComponents/autocomplete/Warning.jsx index 49eb1f73fc..7290dbde84 100644 --- a/src/js/components/sharedComponents/autocomplete/Warning.jsx +++ b/src/js/components/sharedComponents/autocomplete/Warning.jsx @@ -3,6 +3,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from '../icons/Icons'; const defaultProps = { @@ -11,8 +12,8 @@ const defaultProps = { }; const propTypes = { - header: React.PropTypes.string, - description: React.PropTypes.string + header: PropTypes.string, + description: PropTypes.string }; export default class Warning extends React.Component { diff --git a/src/js/components/sharedComponents/checkbox/CheckboxExpandButton.jsx b/src/js/components/sharedComponents/checkbox/CheckboxExpandButton.jsx index a04a0f0bf6..347fc62556 100644 --- a/src/js/components/sharedComponents/checkbox/CheckboxExpandButton.jsx +++ b/src/js/components/sharedComponents/checkbox/CheckboxExpandButton.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from '../icons/Icons'; const defaultProps = { @@ -11,9 +12,9 @@ const defaultProps = { }; const propTypes = { - hidden: React.PropTypes.bool, - toggleExpand: React.PropTypes.func, - arrowState: React.PropTypes.string + hidden: PropTypes.bool, + toggleExpand: PropTypes.func, + arrowState: PropTypes.string }; export default class CheckboxExpandButton extends React.Component { diff --git a/src/js/components/sharedComponents/checkbox/CollapsedCheckboxType.jsx b/src/js/components/sharedComponents/checkbox/CollapsedCheckboxType.jsx index e4ca1be809..e27c2103aa 100644 --- a/src/js/components/sharedComponents/checkbox/CollapsedCheckboxType.jsx +++ b/src/js/components/sharedComponents/checkbox/CollapsedCheckboxType.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import CheckboxExpandButton from './CheckboxExpandButton'; const defaultProps = { @@ -15,13 +16,13 @@ const defaultProps = { }; const propTypes = { - id: React.PropTypes.string, - toggleExpand: React.PropTypes.func, - toggleChildren: React.PropTypes.func, - name: React.PropTypes.string, - selected: React.PropTypes.bool, - hideArrow: React.PropTypes.bool, - arrowState: React.PropTypes.string + id: PropTypes.string, + toggleExpand: PropTypes.func, + toggleChildren: PropTypes.func, + name: PropTypes.string, + selected: PropTypes.bool, + hideArrow: PropTypes.bool, + arrowState: PropTypes.string }; export default class CollapsedCheckboxType extends React.Component { diff --git a/src/js/components/sharedComponents/checkbox/PrimaryCheckboxType.jsx b/src/js/components/sharedComponents/checkbox/PrimaryCheckboxType.jsx index 0b4c49f8c5..5ae6d4ff6d 100644 --- a/src/js/components/sharedComponents/checkbox/PrimaryCheckboxType.jsx +++ b/src/js/components/sharedComponents/checkbox/PrimaryCheckboxType.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Set } from 'immutable'; import SecondaryCheckboxType from './SecondaryCheckboxType'; @@ -11,15 +12,15 @@ import CollapsedCheckboxType from './CollapsedCheckboxType'; import SingleCheckboxType from './SingleCheckboxType'; const propTypes = { - id: React.PropTypes.string, - name: React.PropTypes.string, - filters: React.PropTypes.array, - bulkTypeChange: React.PropTypes.func, - value: React.PropTypes.string, - filterType: React.PropTypes.string, - types: React.PropTypes.object, - selectedCheckboxes: React.PropTypes.object, - enableAnalytics: React.PropTypes.bool + id: PropTypes.string, + name: PropTypes.string, + filters: PropTypes.array, + bulkTypeChange: PropTypes.func, + value: PropTypes.string, + filterType: PropTypes.string, + types: PropTypes.object, + selectedCheckboxes: PropTypes.object, + enableAnalytics: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/sharedComponents/checkbox/SecondaryCheckboxType.jsx b/src/js/components/sharedComponents/checkbox/SecondaryCheckboxType.jsx index b1c99d2036..c20de8fcc1 100644 --- a/src/js/components/sharedComponents/checkbox/SecondaryCheckboxType.jsx +++ b/src/js/components/sharedComponents/checkbox/SecondaryCheckboxType.jsx @@ -4,15 +4,16 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - id: React.PropTypes.string, - code: React.PropTypes.string, - name: React.PropTypes.string, - toggleCheckboxType: React.PropTypes.func, - filterType: React.PropTypes.string, - selectedCheckboxes: React.PropTypes.object, - enableAnalytics: React.PropTypes.bool + id: PropTypes.string, + code: PropTypes.string, + name: PropTypes.string, + toggleCheckboxType: PropTypes.func, + filterType: PropTypes.string, + selectedCheckboxes: PropTypes.object, + enableAnalytics: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/sharedComponents/checkbox/SingleCheckboxType.jsx b/src/js/components/sharedComponents/checkbox/SingleCheckboxType.jsx index b103c9760c..960b8d8e42 100644 --- a/src/js/components/sharedComponents/checkbox/SingleCheckboxType.jsx +++ b/src/js/components/sharedComponents/checkbox/SingleCheckboxType.jsx @@ -4,15 +4,16 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - id: React.PropTypes.string, - code: React.PropTypes.string, - name: React.PropTypes.string, - toggleCheckboxType: React.PropTypes.func, - filterType: React.PropTypes.string, - selectedCheckboxes: React.PropTypes.object, - enableAnalytics: React.PropTypes.bool + id: PropTypes.string, + code: PropTypes.string, + name: PropTypes.string, + toggleCheckboxType: PropTypes.func, + filterType: PropTypes.string, + selectedCheckboxes: PropTypes.object, + enableAnalytics: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/sharedComponents/filterSidebar/FilterExpandButton.jsx b/src/js/components/sharedComponents/filterSidebar/FilterExpandButton.jsx index d0b7ad1d5a..796457a39c 100644 --- a/src/js/components/sharedComponents/filterSidebar/FilterExpandButton.jsx +++ b/src/js/components/sharedComponents/filterSidebar/FilterExpandButton.jsx @@ -4,14 +4,15 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - hideArrow: React.PropTypes.bool, - toggleFilter: React.PropTypes.func, - arrowState: React.PropTypes.string, - name: React.PropTypes.string, - disabled: React.PropTypes.bool + hideArrow: PropTypes.bool, + toggleFilter: PropTypes.func, + arrowState: PropTypes.string, + name: PropTypes.string, + disabled: PropTypes.bool }; export default class FilterExpandButton extends React.Component { diff --git a/src/js/components/sharedComponents/filterSidebar/FilterOption.jsx b/src/js/components/sharedComponents/filterSidebar/FilterOption.jsx index acf2bd1e3e..96787c343f 100644 --- a/src/js/components/sharedComponents/filterSidebar/FilterOption.jsx +++ b/src/js/components/sharedComponents/filterSidebar/FilterOption.jsx @@ -4,16 +4,17 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; import FilterExpandButton from './FilterExpandButton'; const propTypes = { - name: React.PropTypes.string, - component: React.PropTypes.func, - disabled: React.PropTypes.bool, - defaultExpand: React.PropTypes.bool + name: PropTypes.string, + component: PropTypes.func, + disabled: PropTypes.bool, + defaultExpand: PropTypes.bool }; const defaultProps = { diff --git a/src/js/components/sharedComponents/filterSidebar/FilterSidebar.jsx b/src/js/components/sharedComponents/filterSidebar/FilterSidebar.jsx index 68ab158cd7..c456ffdcba 100644 --- a/src/js/components/sharedComponents/filterSidebar/FilterSidebar.jsx +++ b/src/js/components/sharedComponents/filterSidebar/FilterSidebar.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import FilterOption from './FilterOption'; @@ -14,9 +15,9 @@ const defaultProps = { }; const propTypes = { - options: React.PropTypes.arrayOf(React.PropTypes.string), - components: React.PropTypes.arrayOf(React.PropTypes.func), - expanded: React.PropTypes.arrayOf(React.PropTypes.bool) + options: PropTypes.arrayOf(PropTypes.string), + components: PropTypes.arrayOf(PropTypes.func), + expanded: PropTypes.arrayOf(PropTypes.bool) }; export default class FilterSidebar extends React.Component { diff --git a/src/js/components/sharedComponents/header/NavBarGlossaryLink.jsx b/src/js/components/sharedComponents/header/NavBarGlossaryLink.jsx index ba54167009..ade14ef37d 100644 --- a/src/js/components/sharedComponents/header/NavBarGlossaryLink.jsx +++ b/src/js/components/sharedComponents/header/NavBarGlossaryLink.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Glossary } from '../icons/Icons'; const propTypes = { - toggleGlossary: React.PropTypes.func + toggleGlossary: PropTypes.func }; export default class NavBarGlossaryLink extends React.Component { diff --git a/src/js/components/sharedComponents/metaTags/MetaTags.jsx b/src/js/components/sharedComponents/metaTags/MetaTags.jsx index d5a1ab6c7d..4db67e19bf 100644 --- a/src/js/components/sharedComponents/metaTags/MetaTags.jsx +++ b/src/js/components/sharedComponents/metaTags/MetaTags.jsx @@ -4,22 +4,23 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Helmet } from 'react-helmet'; const propTypes = { - og_url: React.PropTypes.string, - og_title: React.PropTypes.string, - og_description: React.PropTypes.string, - og_site_name: React.PropTypes.string, - og_image: React.PropTypes.string, - twitter_title: React.PropTypes.string, - twitter_description: React.PropTypes.string, - twitter_image: React.PropTypes.string, - twitter_url: React.PropTypes.string, - twitter_label1: React.PropTypes.string, - twitter_data1: React.PropTypes.string, - twitter_label2: React.PropTypes.string, - twitter_data2: React.PropTypes.string + og_url: PropTypes.string, + og_title: PropTypes.string, + og_description: PropTypes.string, + og_site_name: PropTypes.string, + og_image: PropTypes.string, + twitter_title: PropTypes.string, + twitter_description: PropTypes.string, + twitter_image: PropTypes.string, + twitter_url: PropTypes.string, + twitter_label1: PropTypes.string, + twitter_data1: PropTypes.string, + twitter_label2: PropTypes.string, + twitter_data2: PropTypes.string }; const defaultProps = { diff --git a/src/js/components/testStyles/IconsExample.jsx b/src/js/components/testStyles/IconsExample.jsx index 9749f3dd10..bb66b69f5b 100644 --- a/src/js/components/testStyles/IconsExample.jsx +++ b/src/js/components/testStyles/IconsExample.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - icon: React.PropTypes.func, - label: React.PropTypes.string + icon: PropTypes.func, + label: PropTypes.string }; export default class IconsExample extends React.Component { diff --git a/src/js/components/testStyles/TestStyleIconItem.jsx b/src/js/components/testStyles/TestStyleIconItem.jsx index d66bbe6be4..cc14b22d37 100644 --- a/src/js/components/testStyles/TestStyleIconItem.jsx +++ b/src/js/components/testStyles/TestStyleIconItem.jsx @@ -4,10 +4,11 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - icon: React.PropTypes.func, - label: React.PropTypes.string + icon: PropTypes.func, + label: PropTypes.string }; export default class TestStyleIconItem extends React.Component { diff --git a/src/js/containers/account/AccountContainer.jsx b/src/js/containers/account/AccountContainer.jsx index 9e12615b92..849bfce995 100644 --- a/src/js/containers/account/AccountContainer.jsx +++ b/src/js/containers/account/AccountContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -22,9 +23,9 @@ import InvalidAccount from 'components/account/InvalidAccount'; import LoadingAccount from 'components/account/LoadingAccount'; const propTypes = { - account: React.PropTypes.object, - params: React.PropTypes.object, - setSelectedAccount: React.PropTypes.func + account: PropTypes.object, + params: PropTypes.object, + setSelectedAccount: PropTypes.func }; const combinedActions = Object.assign({}, diff --git a/src/js/containers/account/awards/AccountAwardsContainer.jsx b/src/js/containers/account/awards/AccountAwardsContainer.jsx index fa4778327d..14a1340366 100644 --- a/src/js/containers/account/awards/AccountAwardsContainer.jsx +++ b/src/js/containers/account/awards/AccountAwardsContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -24,15 +25,15 @@ import AccountAwardsSection from 'components/account/awards/AccountAwardsSection import * as accountActions from 'redux/actions/account/accountActions'; const propTypes = { - account: React.PropTypes.object, - awards: React.PropTypes.instanceOf(Immutable.OrderedSet), - meta: React.PropTypes.object, - filters: React.PropTypes.object, - order: React.PropTypes.object, - setAccountAwardType: React.PropTypes.func, - setAccountAwards: React.PropTypes.func, - appendAccountAwards: React.PropTypes.func, - setAccountAwardOrder: React.PropTypes.func + account: PropTypes.object, + awards: PropTypes.instanceOf(Immutable.OrderedSet), + meta: PropTypes.object, + filters: PropTypes.object, + order: PropTypes.object, + setAccountAwardType: PropTypes.func, + setAccountAwards: PropTypes.func, + appendAccountAwards: PropTypes.func, + setAccountAwardOrder: PropTypes.func }; const tableTypes = [ diff --git a/src/js/containers/account/awards/AccountAwardsHeaderCellContainer.jsx b/src/js/containers/account/awards/AccountAwardsHeaderCellContainer.jsx index 660cd3fdec..df93169cfd 100644 --- a/src/js/containers/account/awards/AccountAwardsHeaderCellContainer.jsx +++ b/src/js/containers/account/awards/AccountAwardsHeaderCellContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -13,7 +14,7 @@ import * as accountActions from 'redux/actions/account/accountActions'; import ResultsTableHeaderCell from 'components/search/table/cells/ResultsTableHeaderCell'; const propTypes = { - setAccountAwardOrder: React.PropTypes.func + setAccountAwardOrder: PropTypes.func }; class AccountAwardsHeaderCellContainer extends React.Component { diff --git a/src/js/containers/account/filters/AccountObjectClassContainer.jsx b/src/js/containers/account/filters/AccountObjectClassContainer.jsx index 5be11f3fa1..71c0b2cf61 100644 --- a/src/js/containers/account/filters/AccountObjectClassContainer.jsx +++ b/src/js/containers/account/filters/AccountObjectClassContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,7 +13,7 @@ import * as accountFilterActions from 'redux/actions/account/accountFilterAction import ObjectClassFilter from 'components/account/filters/objectClass/ObjectClassFilter'; const propTypes = { - toggleObjectClass: React.PropTypes.func + toggleObjectClass: PropTypes.func }; export class AccountObjectClassContainer extends React.Component { diff --git a/src/js/containers/account/filters/AccountProgramActivityContainer.jsx b/src/js/containers/account/filters/AccountProgramActivityContainer.jsx index 3ca5a3ba3b..76c1178025 100644 --- a/src/js/containers/account/filters/AccountProgramActivityContainer.jsx +++ b/src/js/containers/account/filters/AccountProgramActivityContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -15,9 +16,9 @@ import ProgramActivityFilter from 'components/account/filters/programActivity/ProgramActivityFilter'; const propTypes = { - setAvailableProgramActivities: React.PropTypes.func, - toggleProgramActivity: React.PropTypes.func, - account: React.PropTypes.object + setAvailableProgramActivities: PropTypes.func, + toggleProgramActivity: PropTypes.func, + account: PropTypes.object }; export class AccountProgramActivityContainer extends React.Component { diff --git a/src/js/containers/account/filters/AccountTimePeriodContainer.jsx b/src/js/containers/account/filters/AccountTimePeriodContainer.jsx index aea75ff21a..7553757569 100644 --- a/src/js/containers/account/filters/AccountTimePeriodContainer.jsx +++ b/src/js/containers/account/filters/AccountTimePeriodContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import Immutable from 'immutable'; @@ -17,11 +18,11 @@ import TimePeriod from 'components/search/filters/timePeriod/TimePeriod'; const startYear = FiscalYearHelper.earliestFiscalYear; const propTypes = { - updateTimePeriod: React.PropTypes.func, - filterTimePeriodType: React.PropTypes.string, - filterTimePeriodFY: React.PropTypes.instanceOf(Immutable.Set), - filterTimePeriodStart: React.PropTypes.string, - filterTimePeriodEnd: React.PropTypes.string + updateTimePeriod: PropTypes.func, + filterTimePeriodType: PropTypes.string, + filterTimePeriodFY: PropTypes.instanceOf(Immutable.Set), + filterTimePeriodStart: PropTypes.string, + filterTimePeriodEnd: PropTypes.string }; export class AccountTimePeriodContainer extends React.Component { diff --git a/src/js/containers/account/topFilterBar/AccountTopFilterBarContainer.jsx b/src/js/containers/account/topFilterBar/AccountTopFilterBarContainer.jsx index f7baa1f9b9..1f85d52e0d 100644 --- a/src/js/containers/account/topFilterBar/AccountTopFilterBarContainer.jsx +++ b/src/js/containers/account/topFilterBar/AccountTopFilterBarContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { orderBy } from 'lodash'; @@ -16,8 +17,8 @@ import { topFilterGroupGenerator } from import * as accountFilterActions from 'redux/actions/account/accountFilterActions'; const propTypes = { - reduxFilters: React.PropTypes.object, - resetAccountFilters: React.PropTypes.func + reduxFilters: PropTypes.object, + resetAccountFilters: PropTypes.func }; export class AccountTopFilterBarContainer extends React.Component { diff --git a/src/js/containers/account/visualizations/AccountRankVisualizationContainer.jsx b/src/js/containers/account/visualizations/AccountRankVisualizationContainer.jsx index 9215bd64f2..94cd315c4a 100644 --- a/src/js/containers/account/visualizations/AccountRankVisualizationContainer.jsx +++ b/src/js/containers/account/visualizations/AccountRankVisualizationContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -21,8 +22,8 @@ import * as MoneyFormatter from 'helpers/moneyFormatter'; import AccountSearchOperation from 'models/account/queries/AccountSearchOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - account: React.PropTypes.object + reduxFilters: PropTypes.object, + account: PropTypes.object }; export class AccountRankVisualizationContainer extends React.Component { diff --git a/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx b/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx index 0ad7dc9b7c..86ea3289f0 100644 --- a/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx +++ b/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx @@ -3,8 +3,8 @@ * Created by Kevin Li 3/20/17 */ - import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -23,8 +23,8 @@ import AccountSearchCategoryOperation from 'models/account/queries/AccountSearch import { balanceFields, balanceFieldsFiltered, balanceFieldsNonfiltered } from 'dataMapping/accounts/accountFields'; const propTypes = { - reduxFilters: React.PropTypes.object, - account: React.PropTypes.object + reduxFilters: PropTypes.object, + account: PropTypes.object }; export class AccountTimeVisualizationSectionContainer extends React.Component { diff --git a/src/js/containers/agency/AgencyContainer.jsx b/src/js/containers/agency/AgencyContainer.jsx index cb04008013..dfe563be34 100644 --- a/src/js/containers/agency/AgencyContainer.jsx +++ b/src/js/containers/agency/AgencyContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -15,9 +16,9 @@ import * as agencyActions from 'redux/actions/agency/agencyActions'; import AgencyPage from 'components/agency/AgencyPage'; const propTypes = { - params: React.PropTypes.object, - agency: React.PropTypes.object, - setAgencyOverview: React.PropTypes.func + params: PropTypes.object, + agency: PropTypes.object, + setAgencyOverview: PropTypes.func }; export class AgencyContainer extends React.Component { diff --git a/src/js/containers/agency/AgencyFooterContainer.jsx b/src/js/containers/agency/AgencyFooterContainer.jsx index 93aeb31522..bcce134fc2 100644 --- a/src/js/containers/agency/AgencyFooterContainer.jsx +++ b/src/js/containers/agency/AgencyFooterContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -17,9 +18,9 @@ import * as AgencyHelper from 'helpers/agencyHelper'; import AgencyFooter from 'components/agency/footer/AgencyFooter'; const propTypes = { - id: React.PropTypes.string, - clearAllFilters: React.PropTypes.func, - updateSelectedAwardingAgencies: React.PropTypes.func + id: PropTypes.string, + clearAllFilters: PropTypes.func, + updateSelectedAwardingAgencies: PropTypes.func }; export class AgencyFooterContainer extends React.Component { diff --git a/src/js/containers/agency/visualizations/ObjectClassContainer.jsx b/src/js/containers/agency/visualizations/ObjectClassContainer.jsx index 81ebe9b45b..8d6112a7ca 100644 --- a/src/js/containers/agency/visualizations/ObjectClassContainer.jsx +++ b/src/js/containers/agency/visualizations/ObjectClassContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isCancel } from 'axios'; import { reduce } from 'lodash'; @@ -13,8 +14,8 @@ import * as AgencyHelper from 'helpers/agencyHelper'; import ObjectClassTreeMap from 'components/agency/visualizations/objectClass/ObjectClassTreeMap'; const propTypes = { - id: React.PropTypes.string, - activeFY: React.PropTypes.string + id: PropTypes.string, + activeFY: PropTypes.string }; const defaultProps = { diff --git a/src/js/containers/agency/visualizations/ObligatedContainer.jsx b/src/js/containers/agency/visualizations/ObligatedContainer.jsx index 1ef5195efb..b99e389510 100644 --- a/src/js/containers/agency/visualizations/ObligatedContainer.jsx +++ b/src/js/containers/agency/visualizations/ObligatedContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -13,9 +14,9 @@ import ObligatedVisualization from 'components/agency/visualizations/obligated/ObligatedVisualization'; const propTypes = { - id: React.PropTypes.string, - activeFY: React.PropTypes.string, - agencyName: React.PropTypes.string + id: PropTypes.string, + activeFY: PropTypes.string, + agencyName: PropTypes.string }; export class ObligatedContainer extends React.Component { diff --git a/src/js/containers/agency/visualizations/RecipientContainer.jsx b/src/js/containers/agency/visualizations/RecipientContainer.jsx index bdc7fe8cf9..157a112657 100644 --- a/src/js/containers/agency/visualizations/RecipientContainer.jsx +++ b/src/js/containers/agency/visualizations/RecipientContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isCancel } from 'axios'; import { slice } from 'lodash'; @@ -14,8 +15,8 @@ import RecipientVisualization from 'components/agency/visualizations/recipient/RecipientVisualization'; const propTypes = { - id: React.PropTypes.string, - activeFY: React.PropTypes.string + id: PropTypes.string, + activeFY: PropTypes.string }; export default class RecipientContainer extends React.Component { diff --git a/src/js/containers/award/AwardContainer.jsx b/src/js/containers/award/AwardContainer.jsx index b24ad3c0c4..3f3f881ed3 100644 --- a/src/js/containers/award/AwardContainer.jsx +++ b/src/js/containers/award/AwardContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -15,8 +16,8 @@ import * as awardActions from 'redux/actions/award/awardActions'; import AwardSummary from 'models/results/award/AwardSummary'; const propTypes = { - setSelectedAward: React.PropTypes.func, - params: React.PropTypes.object + setSelectedAward: PropTypes.func, + params: PropTypes.object }; export class AwardContainer extends React.Component { diff --git a/src/js/containers/award/subawards/SubawardsContainer.jsx b/src/js/containers/award/subawards/SubawardsContainer.jsx index 84a348884e..1206f4e82c 100644 --- a/src/js/containers/award/subawards/SubawardsContainer.jsx +++ b/src/js/containers/award/subawards/SubawardsContainer.jsx @@ -5,6 +5,7 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -17,12 +18,12 @@ import SubawardItem from 'models/results/award/SubawardItem'; import SubawardsTable from 'components/award/subawards/SubawardsTable'; const propTypes = { - award: React.PropTypes.object, - sort: React.PropTypes.object, - meta: React.PropTypes.object, - setSubawards: React.PropTypes.func, - appendSubawards: React.PropTypes.func, - setSubawardMeta: React.PropTypes.func + award: PropTypes.object, + sort: PropTypes.object, + meta: PropTypes.object, + setSubawards: PropTypes.func, + appendSubawards: PropTypes.func, + setSubawardMeta: PropTypes.func }; const pageLimit = 13; diff --git a/src/js/containers/award/table/AssistanceTransactionsTableContainer.jsx b/src/js/containers/award/table/AssistanceTransactionsTableContainer.jsx index d6f8697184..f07b0df5ba 100644 --- a/src/js/containers/award/table/AssistanceTransactionsTableContainer.jsx +++ b/src/js/containers/award/table/AssistanceTransactionsTableContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -15,12 +16,12 @@ import AssistanceTransaction from 'models/results/transactions/AssistanceTransac import AssistanceTransactionsTable from 'components/award/table/AssistanceTransactionsTable'; const propTypes = { - award: React.PropTypes.object, - setAwardTransactions: React.PropTypes.func, - appendAwardTransactions: React.PropTypes.func, - setTransactionsMeta: React.PropTypes.func, - updateTransactionRenderHash: React.PropTypes.func, - updateTransactionGroupHash: React.PropTypes.func + award: PropTypes.object, + setAwardTransactions: PropTypes.func, + appendAwardTransactions: PropTypes.func, + setTransactionsMeta: PropTypes.func, + updateTransactionRenderHash: PropTypes.func, + updateTransactionGroupHash: PropTypes.func }; const pageLimit = 13; diff --git a/src/js/containers/award/table/ContractTransactionsTableContainer.jsx b/src/js/containers/award/table/ContractTransactionsTableContainer.jsx index 84fb653b0c..062173a7c3 100644 --- a/src/js/containers/award/table/ContractTransactionsTableContainer.jsx +++ b/src/js/containers/award/table/ContractTransactionsTableContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -15,12 +16,12 @@ import ContractTransaction from 'models/results/transactions/ContractTransaction import ContractTransactionsTable from 'components/award/table/ContractTransactionsTable'; const propTypes = { - award: React.PropTypes.object, - setAwardTransactions: React.PropTypes.func, - appendAwardTransactions: React.PropTypes.func, - setTransactionsMeta: React.PropTypes.func, - updateTransactionRenderHash: React.PropTypes.func, - updateTransactionGroupHash: React.PropTypes.func + award: PropTypes.object, + setAwardTransactions: PropTypes.func, + appendAwardTransactions: PropTypes.func, + setTransactionsMeta: PropTypes.func, + updateTransactionRenderHash: PropTypes.func, + updateTransactionGroupHash: PropTypes.func }; const pageLimit = 13; diff --git a/src/js/containers/award/table/FinancialSystemTableContainer.jsx b/src/js/containers/award/table/FinancialSystemTableContainer.jsx index 021dd8e3da..adf7162d5d 100644 --- a/src/js/containers/award/table/FinancialSystemTableContainer.jsx +++ b/src/js/containers/award/table/FinancialSystemTableContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isEqual } from 'lodash'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -20,14 +21,14 @@ import SummaryPageTableMessage from 'components/award/table/SummaryPageTableMess import tableFields from 'dataMapping/contracts/financialSystem'; const propTypes = { - award: React.PropTypes.object, - tableWidth: React.PropTypes.number, - resetFinSys: React.PropTypes.func, - setFinSysData: React.PropTypes.func, - appendFinSysData: React.PropTypes.func, - setFinSysMeta: React.PropTypes.func, - updateTransactionRenderHash: React.PropTypes.func, - updateTransactionGroupHash: React.PropTypes.func + award: PropTypes.object, + tableWidth: PropTypes.number, + resetFinSys: PropTypes.func, + setFinSysData: PropTypes.func, + appendFinSysData: PropTypes.func, + setFinSysMeta: PropTypes.func, + updateTransactionRenderHash: PropTypes.func, + updateTransactionGroupHash: PropTypes.func }; export class FinancialSystemTableContainer extends React.Component { diff --git a/src/js/containers/award/table/LoanTransactionsTableContainer.jsx b/src/js/containers/award/table/LoanTransactionsTableContainer.jsx index 96d6155827..e72a41c2a1 100644 --- a/src/js/containers/award/table/LoanTransactionsTableContainer.jsx +++ b/src/js/containers/award/table/LoanTransactionsTableContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -15,12 +16,12 @@ import LoanTransaction from 'models/results/transactions/LoanTransaction'; import LoanTransactionsTable from 'components/award/table/LoanTransactionsTable'; const propTypes = { - award: React.PropTypes.object, - setAwardTransactions: React.PropTypes.func, - appendAwardTransactions: React.PropTypes.func, - setTransactionsMeta: React.PropTypes.func, - updateTransactionRenderHash: React.PropTypes.func, - updateTransactionGroupHash: React.PropTypes.func + award: PropTypes.object, + setAwardTransactions: PropTypes.func, + appendAwardTransactions: PropTypes.func, + setTransactionsMeta: PropTypes.func, + updateTransactionRenderHash: PropTypes.func, + updateTransactionGroupHash: PropTypes.func }; const pageLimit = 13; diff --git a/src/js/containers/glossary/GlossaryButtonWrapperContainer.jsx b/src/js/containers/glossary/GlossaryButtonWrapperContainer.jsx index 5d38ef8d7f..52c7274203 100644 --- a/src/js/containers/glossary/GlossaryButtonWrapperContainer.jsx +++ b/src/js/containers/glossary/GlossaryButtonWrapperContainer.jsx @@ -4,14 +4,15 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import * as glossaryActions from 'redux/actions/glossary/glossaryActions'; const propTypes = { - dispatch: React.PropTypes.func, - glossary: React.PropTypes.object + dispatch: PropTypes.func, + glossary: PropTypes.object }; export class GlossaryButtonWrapperContainer extends React.Component { diff --git a/src/js/containers/glossary/GlossaryContainer.jsx b/src/js/containers/glossary/GlossaryContainer.jsx index ce06b35ca6..4c221c43a3 100644 --- a/src/js/containers/glossary/GlossaryContainer.jsx +++ b/src/js/containers/glossary/GlossaryContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -17,11 +18,11 @@ import * as glossaryActions from 'redux/actions/glossary/glossaryActions'; import { Definition } from 'redux/reducers/glossary/glossaryReducer'; const propTypes = { - glossary: React.PropTypes.object, - setGlossaryResults: React.PropTypes.func, - showGlossary: React.PropTypes.func, - setGlossaryTerm: React.PropTypes.func, - setGlossaryCache: React.PropTypes.func + glossary: PropTypes.object, + setGlossaryResults: PropTypes.func, + showGlossary: PropTypes.func, + setGlossaryTerm: PropTypes.func, + setGlossaryCache: PropTypes.func }; export class GlossaryContainer extends React.Component { diff --git a/src/js/containers/search/SearchContainer.jsx b/src/js/containers/search/SearchContainer.jsx index d86e4d7621..9203f69699 100644 --- a/src/js/containers/search/SearchContainer.jsx +++ b/src/js/containers/search/SearchContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -20,10 +21,10 @@ import * as SearchHelper from 'helpers/searchHelper'; import SearchPage from 'components/search/SearchPage'; const propTypes = { - params: React.PropTypes.object, - filters: React.PropTypes.object, - populateAllSearchFilters: React.PropTypes.func, - clearAllFilters: React.PropTypes.func + params: PropTypes.object, + filters: PropTypes.object, + populateAllSearchFilters: PropTypes.func, + clearAllFilters: PropTypes.func }; export class SearchContainer extends React.Component { diff --git a/src/js/containers/search/filters/AgencyContainer.jsx b/src/js/containers/search/filters/AgencyContainer.jsx index 500d1bd258..2b8430bf22 100644 --- a/src/js/containers/search/filters/AgencyContainer.jsx +++ b/src/js/containers/search/filters/AgencyContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,8 +13,8 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import Agency from 'components/search/filters/agency/Agency'; const propTypes = { - updateSelectedFundingAgencies: React.PropTypes.func, - updateSelectedAwardingAgencies: React.PropTypes.func + updateSelectedFundingAgencies: PropTypes.func, + updateSelectedAwardingAgencies: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/containers/search/filters/AgencyListContainer.jsx b/src/js/containers/search/filters/AgencyListContainer.jsx index 8b32f0348e..505b8c0fdb 100644 --- a/src/js/containers/search/filters/AgencyListContainer.jsx +++ b/src/js/containers/search/filters/AgencyListContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -16,13 +17,13 @@ import * as SearchHelper from 'helpers/searchHelper'; import * as agencyActions from 'redux/actions/search/agencyActions'; const propTypes = { - setAutocompleteAwardingAgencies: React.PropTypes.func, - setAutocompleteFundingAgencies: React.PropTypes.func, - fundingAgencies: React.PropTypes.array, - awardingAgencies: React.PropTypes.array, - toggleAgency: React.PropTypes.func, - selectedAgencies: React.PropTypes.object, - agencyType: React.PropTypes.string + setAutocompleteAwardingAgencies: PropTypes.func, + setAutocompleteFundingAgencies: PropTypes.func, + fundingAgencies: PropTypes.array, + awardingAgencies: PropTypes.array, + toggleAgency: PropTypes.func, + selectedAgencies: PropTypes.object, + agencyType: PropTypes.string }; export class AgencyListContainer extends React.Component { diff --git a/src/js/containers/search/filters/AwardTypeContainer.jsx b/src/js/containers/search/filters/AwardTypeContainer.jsx index 24f29ad99a..abf79d5a4c 100644 --- a/src/js/containers/search/filters/AwardTypeContainer.jsx +++ b/src/js/containers/search/filters/AwardTypeContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,8 +13,8 @@ import AwardType from 'components/search/filters/awardType/AwardType'; import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; const propTypes = { - toggleAwardType: React.PropTypes.func, - bulkAwardTypeChange: React.PropTypes.func + toggleAwardType: PropTypes.func, + bulkAwardTypeChange: PropTypes.func }; class AwardTypeContainer extends React.Component { diff --git a/src/js/containers/search/filters/KeywordContainer.jsx b/src/js/containers/search/filters/KeywordContainer.jsx index a8d8cf8a88..ce5a6fe632 100644 --- a/src/js/containers/search/filters/KeywordContainer.jsx +++ b/src/js/containers/search/filters/KeywordContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,8 +13,8 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import Keyword from 'components/search/filters/keyword/Keyword'; const propTypes = { - keyword: React.PropTypes.string, - updateTextSearchInput: React.PropTypes.func + keyword: PropTypes.string, + updateTextSearchInput: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/containers/search/filters/TimePeriodContainer.jsx b/src/js/containers/search/filters/TimePeriodContainer.jsx index 777a0b0d60..c20dd43a08 100644 --- a/src/js/containers/search/filters/TimePeriodContainer.jsx +++ b/src/js/containers/search/filters/TimePeriodContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import Immutable from 'immutable'; @@ -17,11 +18,11 @@ import TimePeriod from 'components/search/filters/timePeriod/TimePeriod'; const startYear = FiscalYearHelper.earliestFiscalYear; const propTypes = { - updateTimePeriod: React.PropTypes.func, - filterTimePeriodType: React.PropTypes.string, - filterTimePeriodFY: React.PropTypes.instanceOf(Immutable.Set), - filterTimePeriodStart: React.PropTypes.string, - filterTimePeriodEnd: React.PropTypes.string + updateTimePeriod: PropTypes.func, + filterTimePeriodType: PropTypes.string, + filterTimePeriodFY: PropTypes.instanceOf(Immutable.Set), + filterTimePeriodStart: PropTypes.string, + filterTimePeriodEnd: PropTypes.string }; class TimePeriodContainer extends React.Component { diff --git a/src/js/containers/search/filters/awardAmount/AwardAmountSearchContainer.jsx b/src/js/containers/search/filters/awardAmount/AwardAmountSearchContainer.jsx index ad254cd97d..cfbe586d76 100644 --- a/src/js/containers/search/filters/awardAmount/AwardAmountSearchContainer.jsx +++ b/src/js/containers/search/filters/awardAmount/AwardAmountSearchContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,7 +13,7 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import AwardAmountSearch from 'components/search/filters/awardAmount/AwardAmountSearch'; const propTypes = { - updateAwardAmounts: React.PropTypes.func + updateAwardAmounts: PropTypes.func }; export class AwardAmountSearchContainer extends React.Component { diff --git a/src/js/containers/search/filters/awardID/AwardIDListContainer.jsx b/src/js/containers/search/filters/awardID/AwardIDListContainer.jsx index f2f7e5cdbb..56d8914892 100644 --- a/src/js/containers/search/filters/awardID/AwardIDListContainer.jsx +++ b/src/js/containers/search/filters/awardID/AwardIDListContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; @@ -16,13 +17,13 @@ import * as AwardIDFormatter from 'helpers/awardIDFormatter'; import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; const propTypes = { - toggleAwardID: React.PropTypes.func, - setAutocompleteAwardIDs: React.PropTypes.func, - selectedAwardIDs: React.PropTypes.object, - piid: React.PropTypes.array, - fain: React.PropTypes.array, - uri: React.PropTypes.array, - parent_award__piid: React.PropTypes.array + toggleAwardID: PropTypes.func, + setAutocompleteAwardIDs: PropTypes.func, + selectedAwardIDs: PropTypes.object, + piid: PropTypes.array, + fain: PropTypes.array, + uri: PropTypes.array, + parent_award__piid: PropTypes.array }; export class AwardIDListContainer extends React.Component { diff --git a/src/js/containers/search/filters/awardID/AwardIDSearchContainer.jsx b/src/js/containers/search/filters/awardID/AwardIDSearchContainer.jsx index 9cd7cda2ec..6a9e021ad0 100644 --- a/src/js/containers/search/filters/awardID/AwardIDSearchContainer.jsx +++ b/src/js/containers/search/filters/awardID/AwardIDSearchContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,7 +13,7 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import AwardIDSearch from 'components/search/filters/awardID/AwardIDSearch'; const propTypes = { - updateAwardIDs: React.PropTypes.func + updateAwardIDs: PropTypes.func }; export class AwardIDSearchContainer extends React.Component { diff --git a/src/js/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer.jsx b/src/js/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer.jsx index 8068c514fc..cc5ed291bc 100644 --- a/src/js/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer.jsx +++ b/src/js/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, differenceWith } from 'lodash'; @@ -16,10 +17,10 @@ import * as SearchHelper from 'helpers/searchHelper'; import * as budgetCategoryActions from 'redux/actions/search/budgetCategoryActions'; const propTypes = { - setAutocompleteFederalAccounts: React.PropTypes.func, - autocompleteFederalAccounts: React.PropTypes.array, - updateFederalAccounts: React.PropTypes.func, - federalAccounts: React.PropTypes.object + setAutocompleteFederalAccounts: PropTypes.func, + autocompleteFederalAccounts: PropTypes.array, + updateFederalAccounts: PropTypes.func, + federalAccounts: PropTypes.object }; export class BudgetCategoryAccountContainer extends React.Component { diff --git a/src/js/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer.jsx b/src/js/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer.jsx index 33439d8a05..e7fd76ebd0 100644 --- a/src/js/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer.jsx +++ b/src/js/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, differenceWith } from 'lodash'; @@ -16,10 +17,10 @@ import * as SearchHelper from 'helpers/searchHelper'; import * as budgetCategoryActions from 'redux/actions/search/budgetCategoryActions'; const propTypes = { - setAutocompleteBudgetFunctions: React.PropTypes.func, - autocompleteBudgetFunctions: React.PropTypes.array, - updateBudgetFunctions: React.PropTypes.func, - budgetFunctions: React.PropTypes.object + setAutocompleteBudgetFunctions: PropTypes.func, + autocompleteBudgetFunctions: PropTypes.array, + updateBudgetFunctions: PropTypes.func, + budgetFunctions: PropTypes.object }; export class BudgetCategoryFunctionContainer extends React.Component { diff --git a/src/js/containers/search/filters/budgetCategory/BudgetCategoryOCContainer.jsx b/src/js/containers/search/filters/budgetCategory/BudgetCategoryOCContainer.jsx index bb8f7fde1e..a8ab968d64 100644 --- a/src/js/containers/search/filters/budgetCategory/BudgetCategoryOCContainer.jsx +++ b/src/js/containers/search/filters/budgetCategory/BudgetCategoryOCContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -13,8 +14,8 @@ import BudgetCategoryOCSearch from 'components/search/filters/budgetCategory/BudgetCategoryOCSearch'; const propTypes = { - updateObjectClasses: React.PropTypes.func, - bulkObjectClassesChange: React.PropTypes.func + updateObjectClasses: PropTypes.func, + bulkObjectClassesChange: PropTypes.func }; export class BudgetCategoryOCContainer extends React.Component { diff --git a/src/js/containers/search/filters/budgetCategory/BudgetCategorySearchContainer.jsx b/src/js/containers/search/filters/budgetCategory/BudgetCategorySearchContainer.jsx index 7584069723..7d12136698 100644 --- a/src/js/containers/search/filters/budgetCategory/BudgetCategorySearchContainer.jsx +++ b/src/js/containers/search/filters/budgetCategory/BudgetCategorySearchContainer.jsx @@ -3,8 +3,8 @@ * Created by michaelbray on 3/17/17. */ - import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -13,9 +13,9 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import BudgetCategorySearch from 'components/search/filters/budgetCategory/BudgetCategorySearch'; const propTypes = { - updateSelectedBudgetFunctions: React.PropTypes.func, - updateSelectedFederalAccounts: React.PropTypes.func, - updateSelectedObjectClasses: React.PropTypes.func + updateSelectedBudgetFunctions: PropTypes.func, + updateSelectedFederalAccounts: PropTypes.func, + updateSelectedObjectClasses: PropTypes.func }; export class BudgetCategorySearchContainer extends React.Component { diff --git a/src/js/containers/search/filters/location/LocationListContainer.jsx b/src/js/containers/search/filters/location/LocationListContainer.jsx index 72336568c2..e86bc1f57d 100644 --- a/src/js/containers/search/filters/location/LocationListContainer.jsx +++ b/src/js/containers/search/filters/location/LocationListContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, upperCase, omit, differenceWith } from 'lodash'; @@ -15,11 +16,11 @@ import * as autocompleteActions from 'redux/actions/search/autocompleteActions'; import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; const propTypes = { - selectLocation: React.PropTypes.func, - setAutocompleteLocations: React.PropTypes.func, - selectedLocations: React.PropTypes.object, - locationDomesticForeign: React.PropTypes.string, - autocompleteLocations: React.PropTypes.array + selectLocation: PropTypes.func, + setAutocompleteLocations: PropTypes.func, + selectedLocations: PropTypes.object, + locationDomesticForeign: PropTypes.string, + autocompleteLocations: PropTypes.array }; class LocationListContainer extends React.Component { diff --git a/src/js/containers/search/filters/location/LocationSearchContainer.jsx b/src/js/containers/search/filters/location/LocationSearchContainer.jsx index 4073493b25..d4c6860ec0 100644 --- a/src/js/containers/search/filters/location/LocationSearchContainer.jsx +++ b/src/js/containers/search/filters/location/LocationSearchContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,8 +13,8 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import LocationSearch from 'components/search/filters/location/LocationSearch'; const propTypes = { - updateSelectedLocations: React.PropTypes.func, - updateDomesticForeignSelection: React.PropTypes.func + updateSelectedLocations: PropTypes.func, + updateDomesticForeignSelection: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/containers/search/filters/recipient/RecipientLocationContainer.jsx b/src/js/containers/search/filters/recipient/RecipientLocationContainer.jsx index fd8fe966f8..a50c34a7ef 100644 --- a/src/js/containers/search/filters/recipient/RecipientLocationContainer.jsx +++ b/src/js/containers/search/filters/recipient/RecipientLocationContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, upperCase, omit, differenceWith } from 'lodash'; @@ -15,11 +16,11 @@ import * as recipientActions from 'redux/actions/search/recipientActions'; import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; const propTypes = { - toggleRecipientLocation: React.PropTypes.func, - setAutocompleteRecipientLocations: React.PropTypes.func, - selectedRecipientLocations: React.PropTypes.object, - recipientDomesticForeign: React.PropTypes.string, - autocompleteRecipientLocations: React.PropTypes.array + toggleRecipientLocation: PropTypes.func, + setAutocompleteRecipientLocations: PropTypes.func, + selectedRecipientLocations: PropTypes.object, + recipientDomesticForeign: PropTypes.string, + autocompleteRecipientLocations: PropTypes.array }; export class RecipientLocationContainer extends React.Component { diff --git a/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx b/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx index b8e92cd218..25000d88a0 100644 --- a/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx +++ b/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, union, omit, differenceWith } from 'lodash'; @@ -15,10 +16,10 @@ import * as recipientActions from 'redux/actions/search/recipientActions'; import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; const propTypes = { - toggleRecipient: React.PropTypes.func, - setAutocompleteRecipients: React.PropTypes.func, - selectedRecipients: React.PropTypes.object, - autocompleteRecipients: React.PropTypes.array + toggleRecipient: PropTypes.func, + setAutocompleteRecipients: PropTypes.func, + selectedRecipients: PropTypes.object, + autocompleteRecipients: PropTypes.array }; export class RecipientNameDUNSContainer extends React.Component { diff --git a/src/js/containers/search/filters/recipient/RecipientSearchContainer.jsx b/src/js/containers/search/filters/recipient/RecipientSearchContainer.jsx index d3415c04a2..0f0cd73481 100644 --- a/src/js/containers/search/filters/recipient/RecipientSearchContainer.jsx +++ b/src/js/containers/search/filters/recipient/RecipientSearchContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -12,11 +13,11 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import RecipientSearch from 'components/search/filters/recipient/RecipientSearch'; const propTypes = { - updateSelectedRecipients: React.PropTypes.func, - updateRecipientDomesticForeignSelection: React.PropTypes.func, - toggleRecipientType: React.PropTypes.func, - bulkRecipientTypeChange: React.PropTypes.func, - updateRecipientLocations: React.PropTypes.func + updateSelectedRecipients: PropTypes.func, + updateRecipientDomesticForeignSelection: PropTypes.func, + toggleRecipientType: PropTypes.func, + bulkRecipientTypeChange: PropTypes.func, + updateRecipientLocations: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/containers/search/modals/ExtraModalContainer.jsx b/src/js/containers/search/modals/ExtraModalContainer.jsx index dd3fa6d875..ee82f12e12 100644 --- a/src/js/containers/search/modals/ExtraModalContainer.jsx +++ b/src/js/containers/search/modals/ExtraModalContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { isCancel } from 'axios'; import ExtraModal from 'components/search/modals/ExtraModal'; @@ -11,8 +12,8 @@ import ExtraModal from 'components/search/modals/ExtraModal'; import * as DownloadHelper from 'helpers/downloadHelper'; const propTypes = { - lastReq: React.PropTypes.string, - mounted: React.PropTypes.bool + lastReq: PropTypes.string, + mounted: PropTypes.bool }; export class ExtraModalContainer extends React.Component { diff --git a/src/js/containers/search/table/ResultsTableContainer.jsx b/src/js/containers/search/table/ResultsTableContainer.jsx index 2dbc2fcdda..120a276325 100644 --- a/src/js/containers/search/table/ResultsTableContainer.jsx +++ b/src/js/containers/search/table/ResultsTableContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import Immutable from 'immutable'; @@ -24,23 +25,23 @@ import ResultsTableSection from 'components/search/table/ResultsTableSection'; import SearchActions from 'redux/actions/searchActions'; const propTypes = { - filters: React.PropTypes.object, - rows: React.PropTypes.instanceOf(Immutable.List), - meta: React.PropTypes.object, - batch: React.PropTypes.instanceOf(Immutable.Record), - searchOrder: React.PropTypes.object, - setSearchTableType: React.PropTypes.func, - setSearchPageNumber: React.PropTypes.func, - setSearchOrder: React.PropTypes.func, - clearRecords: React.PropTypes.func, - bulkInsertRecordSet: React.PropTypes.func, - setSearchResultMeta: React.PropTypes.func, - setSearchInFlight: React.PropTypes.func, - triggerBatchSearchUpdate: React.PropTypes.func, - triggerBatchQueryUpdate: React.PropTypes.func, - columnVisibility: React.PropTypes.object, - toggleColumnVisibility: React.PropTypes.func, - reorderColumns: React.PropTypes.func + filters: PropTypes.object, + rows: PropTypes.instanceOf(Immutable.List), + meta: PropTypes.object, + batch: PropTypes.instanceOf(Immutable.Record), + searchOrder: PropTypes.object, + setSearchTableType: PropTypes.func, + setSearchPageNumber: PropTypes.func, + setSearchOrder: PropTypes.func, + clearRecords: PropTypes.func, + bulkInsertRecordSet: PropTypes.func, + setSearchResultMeta: PropTypes.func, + setSearchInFlight: PropTypes.func, + triggerBatchSearchUpdate: PropTypes.func, + triggerBatchQueryUpdate: PropTypes.func, + columnVisibility: PropTypes.object, + toggleColumnVisibility: PropTypes.func, + reorderColumns: PropTypes.func }; const tableTypes = [ diff --git a/src/js/containers/search/table/ResultsTableHeaderCellContainer.jsx b/src/js/containers/search/table/ResultsTableHeaderCellContainer.jsx index 0a90269ee8..196481f1a0 100644 --- a/src/js/containers/search/table/ResultsTableHeaderCellContainer.jsx +++ b/src/js/containers/search/table/ResultsTableHeaderCellContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -19,7 +20,7 @@ const actions = { }; const propTypes = { - setSearchOrder: React.PropTypes.func + setSearchOrder: PropTypes.func }; class ResultsTableHeaderCellContainer extends React.Component { diff --git a/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx b/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx index ab18230e77..439060c5ab 100644 --- a/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx +++ b/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx @@ -4,6 +4,7 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { orderBy } from 'lodash'; @@ -17,8 +18,8 @@ import { topFilterGroupGenerator } from import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; const propTypes = { - reduxFilters: React.PropTypes.object, - updateFilterCount: React.PropTypes.func + reduxFilters: PropTypes.object, + updateFilterCount: PropTypes.func }; export class TopFilterBarContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/geo/GeoVisualizationSectionContainer.jsx b/src/js/containers/search/visualizations/geo/GeoVisualizationSectionContainer.jsx index aed998283e..a7a403c736 100644 --- a/src/js/containers/search/visualizations/geo/GeoVisualizationSectionContainer.jsx +++ b/src/js/containers/search/visualizations/geo/GeoVisualizationSectionContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { uniqueId, isEqual } from 'lodash'; @@ -18,8 +19,8 @@ import * as SearchHelper from 'helpers/searchHelper'; import SearchTransactionOperation from 'models/search/SearchTransactionOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - resultsMeta: React.PropTypes.object + reduxFilters: PropTypes.object, + resultsMeta: PropTypes.object }; export class GeoVisualizationSectionContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/rank/RankVisualizationWrapperContainer.jsx b/src/js/containers/search/visualizations/rank/RankVisualizationWrapperContainer.jsx index d8a879c3f0..aadf9fc4c8 100644 --- a/src/js/containers/search/visualizations/rank/RankVisualizationWrapperContainer.jsx +++ b/src/js/containers/search/visualizations/rank/RankVisualizationWrapperContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual } from 'lodash'; @@ -27,7 +28,7 @@ import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import * as BudgetCategoryHelper from 'helpers/budgetCategoryHelper'; const propTypes = { - reduxFilters: React.PropTypes.object + reduxFilters: PropTypes.object }; export class RankVisualizationWrapperContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer.jsx b/src/js/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer.jsx index e2116f5391..d822babe1e 100644 --- a/src/js/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer.jsx +++ b/src/js/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, max } from 'lodash'; @@ -20,10 +21,10 @@ import SearchTransactionOperation from 'models/search/SearchTransactionOperation import SearchAccountAwardsOperation from 'models/search/SearchAccountAwardsOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - meta: React.PropTypes.object, - budgetFiltersSelected: React.PropTypes.bool, - awardFiltersSelected: React.PropTypes.bool + reduxFilters: PropTypes.object, + meta: PropTypes.object, + budgetFiltersSelected: PropTypes.bool, + awardFiltersSelected: PropTypes.bool }; export class SpendingByAwardingAgencyVisualizationContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer.jsx b/src/js/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer.jsx index 7aec8e18ff..fe21ba4b72 100644 --- a/src/js/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer.jsx +++ b/src/js/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, max } from 'lodash'; @@ -22,10 +23,10 @@ import SearchTransactionOperation from 'models/search/SearchTransactionOperation import SearchAccountAwardsOperation from 'models/search/SearchAccountAwardsOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - meta: React.PropTypes.object, - budgetFiltersSelected: React.PropTypes.bool, - awardFiltersSelected: React.PropTypes.bool + reduxFilters: PropTypes.object, + meta: PropTypes.object, + budgetFiltersSelected: PropTypes.bool, + awardFiltersSelected: PropTypes.bool }; export class SpendingByCFDAVisualizationContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer.jsx b/src/js/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer.jsx index 752317e016..576a1aa4b4 100644 --- a/src/js/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer.jsx +++ b/src/js/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -21,10 +22,10 @@ import SearchAccountAwardsOperation from 'models/search/SearchAccountAwardsOpera import SearchTASCategoriesOperation from 'models/search/SearchTASCategoriesOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - meta: React.PropTypes.object, - budgetFiltersSelected: React.PropTypes.bool, - awardFiltersSelected: React.PropTypes.bool + reduxFilters: PropTypes.object, + meta: PropTypes.object, + budgetFiltersSelected: PropTypes.bool, + awardFiltersSelected: PropTypes.bool }; const fieldNames = { diff --git a/src/js/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer.jsx b/src/js/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer.jsx index ab21206d98..6d70278ac6 100644 --- a/src/js/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer.jsx +++ b/src/js/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, max } from 'lodash'; @@ -20,10 +21,10 @@ import SearchAccountAwardsOperation from 'models/search/SearchAccountAwardsOpera import SearchTASCategoriesOperation from 'models/search/SearchTASCategoriesOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - meta: React.PropTypes.object, - budgetFiltersSelected: React.PropTypes.bool, - awardFiltersSelected: React.PropTypes.bool + reduxFilters: PropTypes.object, + meta: PropTypes.object, + budgetFiltersSelected: PropTypes.bool, + awardFiltersSelected: PropTypes.bool }; export class SpendingByFundingAgencyVisualizationContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer.jsx b/src/js/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer.jsx index 90e9227665..87bb40399c 100644 --- a/src/js/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer.jsx +++ b/src/js/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer.jsx @@ -5,6 +5,7 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -27,10 +28,10 @@ import SearchTransactionOperation from 'models/search/SearchTransactionOperation import SearchAccountAwardsOperation from 'models/search/SearchAccountAwardsOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - meta: React.PropTypes.object, - budgetFiltersSelected: React.PropTypes.bool, - awardFiltersSelected: React.PropTypes.bool + reduxFilters: PropTypes.object, + meta: PropTypes.object, + budgetFiltersSelected: PropTypes.bool, + awardFiltersSelected: PropTypes.bool }; export class SpendingByIndustryCodeVisualizationContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer.jsx b/src/js/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer.jsx index 14689df881..8e68385213 100644 --- a/src/js/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer.jsx +++ b/src/js/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer.jsx @@ -5,6 +5,7 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, max } from 'lodash'; @@ -22,10 +23,10 @@ import SearchTransactionOperation from 'models/search/SearchTransactionOperation import SearchAccountAwardsOperation from 'models/search/SearchAccountAwardsOperation'; const propTypes = { - reduxFilters: React.PropTypes.object, - meta: React.PropTypes.object, - budgetFiltersSelected: React.PropTypes.bool, - awardFiltersSelected: React.PropTypes.bool + reduxFilters: PropTypes.object, + meta: PropTypes.object, + budgetFiltersSelected: PropTypes.bool, + awardFiltersSelected: PropTypes.bool }; export class SpendingByRecipientVisualizationContainer extends React.Component { diff --git a/src/js/containers/search/visualizations/time/TimeVisualizationSectionContainer.jsx b/src/js/containers/search/visualizations/time/TimeVisualizationSectionContainer.jsx index b3e9571d76..0864f96ba1 100644 --- a/src/js/containers/search/visualizations/time/TimeVisualizationSectionContainer.jsx +++ b/src/js/containers/search/visualizations/time/TimeVisualizationSectionContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual } from 'lodash'; @@ -23,8 +24,8 @@ import SearchTransactionOperation from 'models/search/SearchTransactionOperation const combinedActions = Object.assign({}, searchFilterActions, resultsMetaActions); const propTypes = { - reduxFilters: React.PropTypes.object, - setVizTxnSum: React.PropTypes.func + reduxFilters: PropTypes.object, + setVizTxnSum: PropTypes.func }; export class TimeVisualizationSectionContainer extends React.Component { From e0330fd50e50dec45186967191da5275ad5b6876 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Fri, 7 Jul 2017 13:41:14 -0400 Subject: [PATCH 02/97] Initial agency profiles page layout --- src/_scss/custom.scss | 1 + .../pages/agencyProfiles/agencyProfiles.scss | 15 +++++++++ .../pages/agencyProfiles/header/header.scss | 1 + .../agencyProfiles/AgencyProfiles.jsx | 33 +++++++++++++++++++ .../agencyProfiles/AgencyProfilesContent.jsx | 28 ++++++++++++++++ .../agencyProfiles/ProfileSearch.jsx | 17 ++++++++++ .../header/AgencyProfilesHeader.jsx | 20 +++++++++++ .../agencyProfiles/table/AgenciesTable.jsx | 17 ++++++++++ .../AgenciesSearchContainer.jsx | 16 +++++++++ .../agencyProfiles/AgenciesTableContainer.jsx | 16 +++++++++ src/js/containers/router/RouterRoutes.jsx | 9 +++++ src/js/helpers/metaTagHelper.js | 16 +++++++++ 12 files changed, 189 insertions(+) create mode 100644 src/_scss/pages/agencyProfiles/agencyProfiles.scss create mode 100644 src/_scss/pages/agencyProfiles/header/header.scss create mode 100644 src/js/components/agencyProfiles/AgencyProfiles.jsx create mode 100644 src/js/components/agencyProfiles/AgencyProfilesContent.jsx create mode 100644 src/js/components/agencyProfiles/ProfileSearch.jsx create mode 100644 src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx create mode 100644 src/js/components/agencyProfiles/table/AgenciesTable.jsx create mode 100644 src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx create mode 100644 src/js/containers/agencyProfiles/AgenciesTableContainer.jsx diff --git a/src/_scss/custom.scss b/src/_scss/custom.scss index c76e579dec..9f570fab43 100644 --- a/src/_scss/custom.scss +++ b/src/_scss/custom.scss @@ -13,5 +13,6 @@ @import './pages/glossary/glossaryPage'; @import './layouts/article/aboutArticle'; @import './pages/testStyle/testStyle'; +@import './pages/agencyProfiles/agencyProfiles'; // ***** MODALS @import './pages/modals/all'; diff --git a/src/_scss/pages/agencyProfiles/agencyProfiles.scss b/src/_scss/pages/agencyProfiles/agencyProfiles.scss new file mode 100644 index 0000000000..61282f5c62 --- /dev/null +++ b/src/_scss/pages/agencyProfiles/agencyProfiles.scss @@ -0,0 +1,15 @@ +.usa-da-agency-profiles { + @import "layouts/summary/summary"; + + @import "./header/header"; + + .agency-profiles-content { + padding: ($global-pad * 2) rem(35); + .agency-profiles-overview { + text-align: center; + h3 { + margin-top: 0; + } + } + } +} \ No newline at end of file diff --git a/src/_scss/pages/agencyProfiles/header/header.scss b/src/_scss/pages/agencyProfiles/header/header.scss new file mode 100644 index 0000000000..f0d2edb6a2 --- /dev/null +++ b/src/_scss/pages/agencyProfiles/header/header.scss @@ -0,0 +1 @@ +@import "components/pageTitleBar/pageTitleBar"; \ No newline at end of file diff --git a/src/js/components/agencyProfiles/AgencyProfiles.jsx b/src/js/components/agencyProfiles/AgencyProfiles.jsx new file mode 100644 index 0000000000..0d3443122d --- /dev/null +++ b/src/js/components/agencyProfiles/AgencyProfiles.jsx @@ -0,0 +1,33 @@ +/** + * AgencyProfiles.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +import { agencyLandingPageMetaTags } from 'helpers/metaTagHelper'; + +import MetaTags from '../sharedComponents/metaTags/MetaTags'; +import Header from '../sharedComponents/header/Header'; +import Footer from '../sharedComponents/Footer'; + +import AgencyProfilesHeader from './header/AgencyProfilesHeader'; +import AgencyProfilesContent from './AgencyProfilesContent'; + +export default class AgencyProfiles extends React.Component { + render() { + return ( +
+ +
+ +
+ +
+
+
+ ); + } +} diff --git a/src/js/components/agencyProfiles/AgencyProfilesContent.jsx b/src/js/components/agencyProfiles/AgencyProfilesContent.jsx new file mode 100644 index 0000000000..b36fde3049 --- /dev/null +++ b/src/js/components/agencyProfiles/AgencyProfilesContent.jsx @@ -0,0 +1,28 @@ +/** + * AgencyProfilesContent.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +import AgenciesSearchContainer from 'containers/agencyProfiles/AgenciesSearchContainer'; +import AgenciesTableContainer from 'containers/agencyProfiles/AgenciesTableContainer'; + +export default class AgencyProfilesContent extends React.Component { + render() { + return ( +
+
+

Find an Agency Profile.

+
Understand the current spending of agencies in our agency profiles.
+

Sixty-six federal agencies report data to USAspending.gov. These include the + 15 executive departments whose leaders sit on the President's Cabinet, as well + as small independent boards and commissions. They range in size from $700 billion + down to less than $200,000.

+
+ + +
+ ); + } +} diff --git a/src/js/components/agencyProfiles/ProfileSearch.jsx b/src/js/components/agencyProfiles/ProfileSearch.jsx new file mode 100644 index 0000000000..50281b669d --- /dev/null +++ b/src/js/components/agencyProfiles/ProfileSearch.jsx @@ -0,0 +1,17 @@ +/** + * ProfileSearch.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +export default class ProfileSearch extends React.Component { + + render() { + return ( +
+ Search Bar +
+ ); + } +} diff --git a/src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx b/src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx new file mode 100644 index 0000000000..3997fba9ef --- /dev/null +++ b/src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx @@ -0,0 +1,20 @@ +/** + * AgencyProfilesHeader.jsx + * Created by Lizzie Salita + */ + +import React from 'react'; + +export default class AgencyProfilesHeader extends React.Component { + render() { + return ( +
+
+

+ Agency Profiles +

+
+
+ ); + } +} diff --git a/src/js/components/agencyProfiles/table/AgenciesTable.jsx b/src/js/components/agencyProfiles/table/AgenciesTable.jsx new file mode 100644 index 0000000000..f07617c5a2 --- /dev/null +++ b/src/js/components/agencyProfiles/table/AgenciesTable.jsx @@ -0,0 +1,17 @@ +/** + * AgenciesTable.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +export default class AgenciesTable extends React.Component { + + render() { + return ( +
+ Table +
+ ); + } +} diff --git a/src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx b/src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx new file mode 100644 index 0000000000..ea205f17ac --- /dev/null +++ b/src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx @@ -0,0 +1,16 @@ +/** + * AgenciesSearchContainer.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +import ProfileSearch from 'components/agencyProfiles/ProfileSearch'; + +export default class AgenciesSearchContainer extends React.Component { + render() { + return ( + + ); + } +} diff --git a/src/js/containers/agencyProfiles/AgenciesTableContainer.jsx b/src/js/containers/agencyProfiles/AgenciesTableContainer.jsx new file mode 100644 index 0000000000..aa37ad1713 --- /dev/null +++ b/src/js/containers/agencyProfiles/AgenciesTableContainer.jsx @@ -0,0 +1,16 @@ +/** + * AgenciesTableContainer.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +import AgenciesTable from 'components/agencyProfiles/table/AgenciesTable'; + +export default class AgenciesTableContainer extends React.Component { + render() { + return ( + + ); + } +} diff --git a/src/js/containers/router/RouterRoutes.jsx b/src/js/containers/router/RouterRoutes.jsx index 788c8edcf9..bf608ddfa8 100644 --- a/src/js/containers/router/RouterRoutes.jsx +++ b/src/js/containers/router/RouterRoutes.jsx @@ -136,6 +136,15 @@ const routes = { cb(require('components/testStyles/TestStylePage').default); }); } + }, + { + path: '/agencyprofiles', + parent: '/agencyprofiles', + component: (cb) => { + require.ensure([], (require) => { + cb(require('components/agencyProfiles/AgencyProfiles').default); + }); + } } ], notfound: { diff --git a/src/js/helpers/metaTagHelper.js b/src/js/helpers/metaTagHelper.js index 5eab3ed6ee..7c43648af6 100644 --- a/src/js/helpers/metaTagHelper.js +++ b/src/js/helpers/metaTagHelper.js @@ -123,6 +123,22 @@ export const agencyPageMetaTags = { twitter_data2: "" }; +export const agencyLandingPageMetaTags = { + og_url: "https://beta.usaspending.gov/", + og_title: "Beta.USAspending.gov", + og_description: "Beta.USAspending.gov is the new official source of accessible, searchable and reliable spending data for the U.S. Government.", + og_site_name: "Beta.USAspending.gov", + og_image: `${productionURL}${imgDirectory}${facebookImage}`, + twitter_title: "Beta.USAspending.gov", + twitter_description: "Beta.USAspending.gov is the new official source of accessible, searchable and reliable spending data for the U.S. Government.", + twitter_image: `${productionURL}${imgDirectory}${twitterImage}`, + twitter_url: "https://beta.usaspending.gov/", + twitter_label1: "", + twitter_data1: "", + twitter_label2: "", + twitter_data2: "" +}; + export const stylePageMetaTags = { og_url: "https://beta.usaspending.gov/", og_title: "Beta.USAspending.gov", From 79c163ef8e3d2b327963380fb1b4de278997300b Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Tue, 11 Jul 2017 11:10:58 -0400 Subject: [PATCH 03/97] Initial checkin --- .../search/filters/cfda/CFDASearch.jsx | 37 ++++ .../search/filters/cfda/SelectedCFDA.jsx | 37 ++++ .../search/filters/cfda/ShownCFDA.jsx | 29 +++ .../search/filters/cfda/CFDAListContainer.jsx | 176 ++++++++++++++++++ .../filters/cfda/CFDASearchContainer.jsx | 72 +++++++ src/js/helpers/cfdaFormatter.js | 26 +++ .../actions/search/searchFilterActions.js | 7 + .../search/filters/CFDAFilterFunctions.js | 0 .../reducers/search/searchFiltersReducer.js | 15 +- 9 files changed, 397 insertions(+), 2 deletions(-) create mode 100644 src/js/components/search/filters/cfda/CFDASearch.jsx create mode 100644 src/js/components/search/filters/cfda/SelectedCFDA.jsx create mode 100644 src/js/components/search/filters/cfda/ShownCFDA.jsx create mode 100644 src/js/containers/search/filters/cfda/CFDAListContainer.jsx create mode 100644 src/js/containers/search/filters/cfda/CFDASearchContainer.jsx create mode 100644 src/js/helpers/cfdaFormatter.js create mode 100644 src/js/redux/reducers/search/filters/CFDAFilterFunctions.js diff --git a/src/js/components/search/filters/cfda/CFDASearch.jsx b/src/js/components/search/filters/cfda/CFDASearch.jsx new file mode 100644 index 0000000000..f6f4dfe3c3 --- /dev/null +++ b/src/js/components/search/filters/cfda/CFDASearch.jsx @@ -0,0 +1,37 @@ +/** + * CFDASearch.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; + +import CFDAListContainer from 'containers/search/filters/cfda/CFDAListContainer'; +import SelectedCFDA from './SelectedCFDA'; + +const propTypes = { + selectCFDA: React.PropTypes.func, + removeCFDA: React.PropTypes.func, + selectedCFDA: React.PropTypes.object +}; + +export default class LocationSearch extends React.Component { + render() { + let selectedLocations = null; + if (this.props.selectedCFDA.size > 0) { + selectedLocations = (); + } + + return ( +
+
+ + {selectedLocations} +
+
+ ); + } +} + +CFDASearch.propTypes = propTypes; diff --git a/src/js/components/search/filters/cfda/SelectedCFDA.jsx b/src/js/components/search/filters/cfda/SelectedCFDA.jsx new file mode 100644 index 0000000000..7b3a173ff3 --- /dev/null +++ b/src/js/components/search/filters/cfda/SelectedCFDA.jsx @@ -0,0 +1,37 @@ +/** + * SelectedCFDA.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; + +import * as CFDAFormatter from 'helpers/cfdaFormatter'; +import ShownCFDA from './ShownCFDA'; + +const propTypes = { + selectedCFDA: React.PropTypes.object, + removeCFDA: React.PropTypes.func +}; + +export default class SelectedCFDA extends React.Component { + render() { + const shownCFDA = []; + this.props.selectedCFDA.entrySeq().forEach((entry) => { + const key = entry[0]; + const cfda = entry[1]; + const value = (); + shownCFDA.push(value); + }); + + return ( +
+ {shownCFDA} +
+ ); + } +} +SelectedCFDA.propTypes = propTypes; diff --git a/src/js/components/search/filters/cfda/ShownCFDA.jsx b/src/js/components/search/filters/cfda/ShownCFDA.jsx new file mode 100644 index 0000000000..ee8be61906 --- /dev/null +++ b/src/js/components/search/filters/cfda/ShownCFDA.jsx @@ -0,0 +1,29 @@ +/** + * ShownLocation.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; +import * as Icons from 'components/sharedComponents/icons/Icons'; + +const propTypes = { + removeCFDA: React.PropTypes.func, + label: React.PropTypes.string +}; + +export default class ShownCFDA extends React.Component { + + render() { + return ( + + ); + } +} +ShownCFDA.propTypes = propTypes; diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx new file mode 100644 index 0000000000..2efc351d7b --- /dev/null +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -0,0 +1,176 @@ +/** +* CFDAListContainer.jsx +* Created by Emily Gullo 07/10/2017 +**/ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { isEqual, upperCase, omit, differenceWith } from 'lodash'; +import { isCancel } from 'axios'; + +import * as SearchHelper from 'helpers/searchHelper'; +import * as autocompleteActions from 'redux/actions/search/autocompleteActions'; + +import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; + +const propTypes = { + selectCFDA: React.PropTypes.func, + setAutocompleteCFDA: React.PropTypes.func, + selectedCFDA: React.PropTypes.object, + autocompleteCFDA: React.PropTypes.array +}; + +class CFDAListContainer extends React.Component { + constructor(props) { + super(props); + + this.state = { + cfdaSearchString: '', + autocompleteCFDA: [], + noResults: false + }; + + this.handleTextInput = this.handleTextInput.bind(this); + this.clearAutocompleteSuggestions = this.clearAutocompleteSuggestions.bind(this); + this.timeout = null; + } + + componentDidMount() { + this.parseAutocompleteLocations(this.props.autocompleteCFDA); + } + + componentWillReceiveProps(nextProps) { + if (!isEqual(nextProps.autocompleteCFDA, this.props.autocompleteCFDA)) { + this.parseAutocompleteLocations(nextProps.autocompleteCFDA); + } + } + + parseAutocompleteLocations(locations) { + const values = []; + if (locations.length > 0) { + locations.forEach((item) => { + let placeType = upperCase(item.place_type); + if (item.parent !== null && + (item.place_type !== null && item.place_type !== 'COUNTRY')) { + placeType += ` in ${item.parent}`; + } + + values.push({ + title: item.place, + subtitle: placeType, + data: item + }); + }); + } + + this.setState({ + autocompleteLocations: values + }); + } + + queryAutocompleteLocations(input) { + this.setState({ + noResults: false + }); + + // Only search if input is 2 or more characters + if (input.length >= 2) { + this.setState({ + locationSearchString: input + }); + + if (this.locationSearchRequest) { + // A request is currently in-flight, cancel it + this.locationSearchRequest.cancel(); + } + + const locSearchParams = { + value: this.state.locationSearchString, + usage: "place_of_performance" + }; + + this.locationSearchRequest = SearchHelper.fetchLocations(locSearchParams); + + this.locationSearchRequest.promise + .then((res) => { + const data = res.data; + let autocompleteData = []; + + // Remove 'identifier' from selected locations to enable comparison + const selectedLocations = this.props.selectedCFDA.toArray() + .map((location) => omit(location, 'identifier')); + + // Filter out any selectedLocations that may be in the result set + if (selectedLocations && selectedLocations.length > 0) { + autocompleteData = differenceWith(data, selectedLocations, isEqual); + } + else { + autocompleteData = data; + } + + this.setState({ + noResults: autocompleteData.length === 0 + }); + + // Add search results to Redux + this.props.setAutocompleteCFDA(autocompleteData); + }) + .catch((err) => { + if (!isCancel(err)) { + this.setState({ + noResults: true + }); + } + }); + } + else if (this.locationSearchRequest) { + // A request is currently in-flight, cancel it + this.locationSearchRequest.cancel(); + } + } + + clearAutocompleteSuggestions() { + this.props.setAutocompleteCFDA([]); + } + + handleTextInput(locationInput) { + // Clear existing locations to ensure user can't select an old or existing one + this.props.setAutocompleteCFDA([]); + + // Grab input, clear any exiting timeout + const input = locationInput.target.value; + window.clearTimeout(this.timeout); + + // Perform search if user doesn't type again for 300ms + this.timeout = window.setTimeout(() => { + this.queryAutocompleteLocations(input); + }, 300); + } + + render() { + return ( + { + this.cfdaList = input; + }} + clearAutocompleteSuggestions={this.clearAutocompleteSuggestions} + noResults={this.state.noResults} /> + ); + } + +} + +export default connect( + (state) => ({ autocompleteCFDA: state.autocompleteCFDA }), + (dispatch) => bindActionCreators(autocompleteActions, dispatch) +)(CFDAListContainer); + +CFDAListContainer.propTypes = propTypes; diff --git a/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx b/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx new file mode 100644 index 0000000000..520887c50b --- /dev/null +++ b/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx @@ -0,0 +1,72 @@ +/** + * CFDASearchContainer.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; + +import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; + +import CFDASearch from 'components/search/filters/cfda/CFDASearch'; + +const propTypes = { + updateSelectedCFDA: React.PropTypes.func +}; + +const ga = require('react-ga'); + +class CFDASearchContainer extends React.Component { + + static logPlaceFilterEvent(place) { + ga.event({ + category: 'Search Page Filter Applied', + action: `Applied CFDA Filter`, + label: place.toLowerCase() + }); + } + + constructor(props) { + super(props); + + // Bind functions + this.selectCFDA = this.selectCFDA.bind(this); + this.removeCFDA = this.removeCFDA.bind(this); + } + + selectCFDA(cfda, isValid) { + // If cfda exists and is valid + if (cfda !== null && isValid) { + const updateParams = {}; + updateParams.cfda = cfda; + this.props.updateSelectedCFDA(updateParams); + + // Analytics + CFDASearchContainer.logPlaceFilterEvent(cfda.place); + } + } + + removeCFDA(cfda) { + const updateParams = {}; + updateParams.cfda = cfda; + this.props.updateSelectedCFDA(updateParams); + } + + render() { + return ( + + ); + } +} + +CFDASearchContainer.propTypes = propTypes; + +export default connect( + (state) => ({ + selectedCFDA: state.filters.selectedCFDA }), + (dispatch) => bindActionCreators(searchFilterActions, dispatch) +)(CFDASearchContainer); diff --git a/src/js/helpers/cfdaFormatter.js b/src/js/helpers/cfdaFormatter.js new file mode 100644 index 0000000000..79cde79fa3 --- /dev/null +++ b/src/js/helpers/cfdaFormatter.js @@ -0,0 +1,26 @@ +/** + * cfdaFormatter.js + * Created by Emily Gullo on 07/10/2017 + */ + +import { startCase, toLower } from 'lodash'; + +/* eslint-disable import/prefer-default-export */ +// We only have one export but want to maintain consistency with other helpers +export const formatCFDA = (cfda) => { + let displayValue = ''; + + if (cfda.place_type !== null) { + displayValue = `${startCase(toLower(cfda.place_type))} | `; + } + + displayValue += `${cfda.place}`; + + if (cfda.parent !== null && + (cfda.place_type !== null && cfda.place_type !== 'COUNTRY')) { + displayValue += `, ${cfda.parent}`; + } + + return displayValue; +}; +/* eslint-enable import/prefer-default-export */ diff --git a/src/js/redux/actions/search/searchFilterActions.js b/src/js/redux/actions/search/searchFilterActions.js index a79d9c247e..3f4fa5cf40 100644 --- a/src/js/redux/actions/search/searchFilterActions.js +++ b/src/js/redux/actions/search/searchFilterActions.js @@ -137,6 +137,13 @@ export const updateAwardAmounts = (state) => ({ awardAmounts: state }); +// CFDA Filter + +export const updateSelectedCFDA = (state) => ({ + type: 'UPDATE_SELECTED_CFDA', + cfda: state.cfda +}); + // Generic export const setSearchOrder = (state) => ({ diff --git a/src/js/redux/reducers/search/filters/CFDAFilterFunctions.js b/src/js/redux/reducers/search/filters/CFDAFilterFunctions.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/js/redux/reducers/search/searchFiltersReducer.js b/src/js/redux/reducers/search/searchFiltersReducer.js index 0e457b11be..abd534e021 100644 --- a/src/js/redux/reducers/search/searchFiltersReducer.js +++ b/src/js/redux/reducers/search/searchFiltersReducer.js @@ -12,6 +12,7 @@ import * as RecipientFilterFunctions from './filters/recipientFilterFunctions'; import * as AwardIDFilterFunctions from './filters/awardIDFilterFunctions'; import * as AwardAmountFilterFunctions from './filters/awardAmountFilterFunctions'; import * as BudgetCategoryFilterFunctions from './filters/budgetCategoryFilterFunctions'; +import * as CFDAFilterFunctions from './filters/CFDAFilterFunctions'; // update this version when changes to the reducer structure are made // frontend will reject inbound hashed search filter sets with different versions because the @@ -31,7 +32,8 @@ export const requiredTypes = { selectedRecipientLocations: OrderedMap, awardType: Set, selectedAwardIDs: OrderedMap, - awardAmounts: OrderedMap + awardAmounts: OrderedMap, + selectedCFDA: OrderedMap }; export const initialState = { @@ -53,7 +55,8 @@ export const initialState = { selectedRecipientLocations: new OrderedMap(), awardType: new Set(), selectedAwardIDs: new OrderedMap(), - awardAmounts: new OrderedMap() + awardAmounts: new OrderedMap(), + selectedCFDA: new OrderedMap() }; const searchFiltersReducer = (state = initialState, action) => { @@ -197,6 +200,14 @@ const searchFiltersReducer = (state = initialState, action) => { }); } + // CFDA Filter + case 'UPDATE_SELECTED_CFDA': { + return Object.assign({}, state, { + selectedCFDA: CFDAFilterFunctions.updateSelectedCFDA( + state.selectedCFDA, action.cfda) + }); + } + // Generic case 'UPDATE_SEARCH_FILTER_GENERIC': { return Object.assign({}, state, { From 93715c2428611e9265619bc6bf92806d778eefc6 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Tue, 11 Jul 2017 13:33:32 -0400 Subject: [PATCH 04/97] Fixed PropTypes migration in BaseIcon --- src/js/components/sharedComponents/icons/BaseIcon.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/components/sharedComponents/icons/BaseIcon.jsx b/src/js/components/sharedComponents/icons/BaseIcon.jsx index 21dded4b5e..1c64f84570 100644 --- a/src/js/components/sharedComponents/icons/BaseIcon.jsx +++ b/src/js/components/sharedComponents/icons/BaseIcon.jsx @@ -3,12 +3,12 @@ * Created by Kevin Li 4/25/2016 */ -import React, { PropTypes } from 'react'; +import React from 'react'; +import PropTypes from 'prop-types'; import svg4everybody from 'svg4everybody'; import IconSingleton from './iconSingleton'; - const propTypes = { iconClass: PropTypes.string.isRequired, iconName: PropTypes.string.isRequired, From 86c81d59f13e42c78f7d075cdbdf4a81167cd075 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Tue, 11 Jul 2017 16:52:58 -0400 Subject: [PATCH 05/97] Updating `react-day-picker` and fixing event handling issues --- package.json | 2 +- src/js/components/sharedComponents/DatePicker.jsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index fea0a18268..cf6f5ad5f1 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "react-addons-update": "15.6.0", "react-aria-modal": "^2.6.0", "react-custom-scrollbars": "^4.1.2", - "react-day-picker": "^3.1.1", + "react-day-picker": "^6.1.0", "react-dnd": "^2.4.0", "react-dnd-html5-backend": "^2.4.1", "react-dom": "15.6.1", diff --git a/src/js/components/sharedComponents/DatePicker.jsx b/src/js/components/sharedComponents/DatePicker.jsx index facdd044b4..393b7807ac 100644 --- a/src/js/components/sharedComponents/DatePicker.jsx +++ b/src/js/components/sharedComponents/DatePicker.jsx @@ -109,7 +109,8 @@ export default class DatePicker extends React.Component { } } - handleDatePick(e, day) { + handleDatePick(day) { + console.log(day); this.props.onDateChange(day, this.props.type); this.props.hideError(); // close the popup if is shown @@ -121,6 +122,7 @@ export default class DatePicker extends React.Component { } handleTypedDate(e) { + console.log(e.target.value); // update the string state of the input field this.setState({ inputValue: e.target.value @@ -147,7 +149,7 @@ export default class DatePicker extends React.Component { const date = moment(this.state.inputValue, format); if (date.isValid()) { // it's a valid date - this.handleDatePick(null, date.toDate()); + this.handleDatePick(date.toDate()); } }); } From 9a5df839144d98894282474be8d9190cc0b9e413 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Tue, 11 Jul 2017 17:04:32 -0400 Subject: [PATCH 06/97] Update enzyme to convert to react-dom/test-utils usage --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index cf6f5ad5f1..90042ae430 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "usaspending-website", "version": "2.5.0", "description": "USAspending Website", + "repository": "fedspendingtransparency/usaspending-website", "main": "src/entry.js", "scripts": { "start": "./node_modules/.bin/webpack-dev-server --progress --config ./webpack/webpack.dev.config.js", @@ -36,7 +37,7 @@ "babel-preset-react": "^6.24.1", "clean-webpack-plugin": "^0.1.16", "css-loader": "^0.28.4", - "enzyme": "^2.7.0", + "enzyme": "^2.9.1", "eslint": "^3.17.1", "eslint-config-airbnb": "^13.0.0", "eslint-plugin-import": "^2.1.0", From 843de178b0afaa3b9ad3d2866501be8db55f4450 Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Wed, 12 Jul 2017 14:55:06 -0400 Subject: [PATCH 07/97] Update container --- src/js/components/search/SearchSidebar.jsx | 3 +- .../search/filters/cfda/CFDASearch.jsx | 3 +- .../search/filters/cfda/CFDAListContainer.jsx | 42 +++++++++---------- src/js/models/search/SearchOperation.js | 11 +++++ .../models/search/queryBuilders/CFDAQuery.js | 26 ++++++++++++ 5 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 src/js/models/search/queryBuilders/CFDAQuery.js diff --git a/src/js/components/search/SearchSidebar.jsx b/src/js/components/search/SearchSidebar.jsx index 5408acef42..9ca80ea0ac 100644 --- a/src/js/components/search/SearchSidebar.jsx +++ b/src/js/components/search/SearchSidebar.jsx @@ -16,6 +16,7 @@ import KeywordContainer from 'containers/search/filters/KeywordContainer'; import AwardIDSearchContainer from 'containers/search/filters/awardID/AwardIDSearchContainer'; import AwardAmountSearchContainer from 'containers/search/filters/awardAmount/AwardAmountSearchContainer'; +import CFDASearchContainer from 'containers/search/filters/cfda/CFDASearchContainer'; import { Filter as FilterIcon } from 'components/sharedComponents/icons/Icons'; import FilterSidebar from 'components/sharedComponents/filterSidebar/FilterSidebar'; @@ -44,7 +45,7 @@ const filters = { AwardTypeContainer, AwardIDSearchContainer, AwardAmountSearchContainer, - null + CFDASearchContainer ] }; diff --git a/src/js/components/search/filters/cfda/CFDASearch.jsx b/src/js/components/search/filters/cfda/CFDASearch.jsx index f6f4dfe3c3..e1a78cbfe4 100644 --- a/src/js/components/search/filters/cfda/CFDASearch.jsx +++ b/src/js/components/search/filters/cfda/CFDASearch.jsx @@ -14,7 +14,7 @@ const propTypes = { selectedCFDA: React.PropTypes.object }; -export default class LocationSearch extends React.Component { +export default class CFDASearch extends React.Component { render() { let selectedLocations = null; if (this.props.selectedCFDA.size > 0) { @@ -26,6 +26,7 @@ export default class LocationSearch extends React.Component { return (
+

CFDA

{selectedLocations}
diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index 2efc351d7b..41fdea269d 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -37,19 +37,19 @@ class CFDAListContainer extends React.Component { } componentDidMount() { - this.parseAutocompleteLocations(this.props.autocompleteCFDA); + this.parseAutocompleteCFDA(this.props.autocompleteCFDA); } componentWillReceiveProps(nextProps) { if (!isEqual(nextProps.autocompleteCFDA, this.props.autocompleteCFDA)) { - this.parseAutocompleteLocations(nextProps.autocompleteCFDA); + this.parseAutocompleteCFDA(nextProps.autocompleteCFDA); } } - parseAutocompleteLocations(locations) { + parseAutocompleteCFDA(cfda) { const values = []; - if (locations.length > 0) { - locations.forEach((item) => { + if (cfda.length > 0) { + cfda.forEach((item) => { let placeType = upperCase(item.place_type); if (item.parent !== null && (item.place_type !== null && item.place_type !== 'COUNTRY')) { @@ -65,11 +65,11 @@ class CFDAListContainer extends React.Component { } this.setState({ - autocompleteLocations: values + autocompleteCFDA: values }); } - queryAutocompleteLocations(input) { + queryAutocompleteCFDA(input) { this.setState({ noResults: false }); @@ -77,33 +77,33 @@ class CFDAListContainer extends React.Component { // Only search if input is 2 or more characters if (input.length >= 2) { this.setState({ - locationSearchString: input + cfdaSearchString: input }); - if (this.locationSearchRequest) { + if (this.cfdaSearchRequest) { // A request is currently in-flight, cancel it this.locationSearchRequest.cancel(); } - const locSearchParams = { - value: this.state.locationSearchString, - usage: "place_of_performance" + const cfdaSearchParams = { + value: this.state.cfdaSearchString, + usage: "cfda" }; - this.locationSearchRequest = SearchHelper.fetchLocations(locSearchParams); + this.cfdaSearchRequest = SearchHelper.fetchCFDA(cfdaSearchParams); - this.locationSearchRequest.promise + this.cfdaSearchRequest.promise .then((res) => { const data = res.data; let autocompleteData = []; // Remove 'identifier' from selected locations to enable comparison - const selectedLocations = this.props.selectedCFDA.toArray() - .map((location) => omit(location, 'identifier')); + const selectedCFDA = this.props.selectedCFDA.toArray() + .map((cfda) => omit(cfda, 'identifier')); // Filter out any selectedLocations that may be in the result set - if (selectedLocations && selectedLocations.length > 0) { - autocompleteData = differenceWith(data, selectedLocations, isEqual); + if (selectedCFDA && selectedCFDA.length > 0) { + autocompleteData = differenceWith(data, selectedCFDA, isEqual); } else { autocompleteData = data; @@ -124,9 +124,9 @@ class CFDAListContainer extends React.Component { } }); } - else if (this.locationSearchRequest) { + else if (this.cfdaSearchRequest) { // A request is currently in-flight, cancel it - this.locationSearchRequest.cancel(); + this.cfdaSearchRequest.cancel(); } } @@ -144,7 +144,7 @@ class CFDAListContainer extends React.Component { // Perform search if user doesn't type again for 300ms this.timeout = window.setTimeout(() => { - this.queryAutocompleteLocations(input); + this.queryAutocompleteCFDA(input); }, 300); } diff --git a/src/js/models/search/SearchOperation.js b/src/js/models/search/SearchOperation.js index 1f5db5d365..f3be79367b 100644 --- a/src/js/models/search/SearchOperation.js +++ b/src/js/models/search/SearchOperation.js @@ -13,6 +13,7 @@ import * as RecipientQuery from './queryBuilders/RecipientQuery'; import * as KeywordQuery from './queryBuilders/KeywordQuery'; import * as AwardIDQuery from './queryBuilders/AwardIDQuery'; import * as AwardAmountQuery from './queryBuilders/AwardAmountQuery'; +import * as CFDAQuery from './queryBuilders/CFDAQuery'; class SearchOperation { constructor() { @@ -45,6 +46,8 @@ class SearchOperation { this.awardAmounts = []; + this.selectedCFDA = []; + this.searchContext = 'award'; } @@ -77,6 +80,8 @@ class SearchOperation { this.selectedAwardIDs = state.selectedAwardIDs.toArray(); this.awardAmounts = state.awardAmounts.toArray(); + + this.selectedCFDA = state.selectedCFDA.toArray(); } commonParams() { @@ -152,6 +157,12 @@ class SearchOperation { } } + // Add cfda query + if (this.selectedCFDA.length > 0) { + filters.push(CFDAQuery.buildCFDAQuery( + this.selectedCFDA, this.searchContext)); + } + return filters; } diff --git a/src/js/models/search/queryBuilders/CFDAQuery.js b/src/js/models/search/queryBuilders/CFDAQuery.js new file mode 100644 index 0000000000..c199f926e0 --- /dev/null +++ b/src/js/models/search/queryBuilders/CFDAQuery.js @@ -0,0 +1,26 @@ +/** + * Created by Emily Gullo 07/12/2017 + */ + +import * as FilterFields from 'dataMapping/search/filterFields'; +/* eslint-disable import/prefer-default-export */ +// We only have one export but want to maintain consistency with other queries +export const buildCFDAQuery = (cfdas, searchContext = 'award') => { + const field = FilterFields[`${searchContext}Fields`].cfda; + + const cfdaSet = []; + + // Push IDs of selected Awards + cfdas.forEach((cfda) => { + cfdaSet.push(cfda.id); + }); + + const filter = { + field, + operation: "in", + value: cfdaSet + }; + + return filter; +}; +/* eslint-enable import/prefer-default-export */ From 68b11dd1af0077f301192267af894d4cb5e7f5a5 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Wed, 12 Jul 2017 17:52:43 -0400 Subject: [PATCH 08/97] Refactoring, agencies table with mock data --- src/_scss/custom.scss | 2 +- .../agencyLanding/agencyLandingPage.scss | 30 +++ .../agencyLanding/agencyLandingSearch.scss | 36 ++++ .../header/header.scss | 0 .../pages/agencyLanding/table/table.scss | 5 + .../pages/agencyProfiles/agencyProfiles.scss | 15 -- .../agencyLanding/AgencyLandingPage.jsx | 43 ++++ .../AgencyLandingResultsSection.jsx | 79 +++++++ .../agencyLanding/AgencyLandingSearchBar.jsx | 34 +++ .../header/AgencyLandingHeader.jsx} | 6 +- .../table/AgencyLandingTable.jsx | 143 ++++++++++++ .../agencyProfiles/AgencyProfiles.jsx | 33 --- .../agencyProfiles/AgencyProfilesContent.jsx | 28 --- .../agencyProfiles/ProfileSearch.jsx | 17 -- .../agencyProfiles/table/AgenciesTable.jsx | 17 -- .../agencyLanding/AgencyLandingContainer.jsx | 204 ++++++++++++++++++ .../AgencyLandingHeaderCellContainer.jsx | 56 +++++ .../AgenciesSearchContainer.jsx | 16 -- .../agencyProfiles/AgenciesTableContainer.jsx | 16 -- src/js/containers/router/RouterRoutes.jsx | 2 +- .../agencyLanding/agenciesTableFields.js | 18 ++ src/js/helpers/agencyLandingHelper.js | 41 ++++ src/js/helpers/glossaryHelper.js | 2 +- .../agencyLanding/agencyLandingActions.js | 18 ++ .../agencyLanding/agencyLandingReducer.js | 47 ++++ src/js/redux/reducers/index.js | 4 +- 26 files changed, 763 insertions(+), 149 deletions(-) create mode 100644 src/_scss/pages/agencyLanding/agencyLandingPage.scss create mode 100644 src/_scss/pages/agencyLanding/agencyLandingSearch.scss rename src/_scss/pages/{agencyProfiles => agencyLanding}/header/header.scss (100%) create mode 100644 src/_scss/pages/agencyLanding/table/table.scss delete mode 100644 src/_scss/pages/agencyProfiles/agencyProfiles.scss create mode 100644 src/js/components/agencyLanding/AgencyLandingPage.jsx create mode 100644 src/js/components/agencyLanding/AgencyLandingResultsSection.jsx create mode 100644 src/js/components/agencyLanding/AgencyLandingSearchBar.jsx rename src/js/components/{agencyProfiles/header/AgencyProfilesHeader.jsx => agencyLanding/header/AgencyLandingHeader.jsx} (72%) create mode 100644 src/js/components/agencyLanding/table/AgencyLandingTable.jsx delete mode 100644 src/js/components/agencyProfiles/AgencyProfiles.jsx delete mode 100644 src/js/components/agencyProfiles/AgencyProfilesContent.jsx delete mode 100644 src/js/components/agencyProfiles/ProfileSearch.jsx delete mode 100644 src/js/components/agencyProfiles/table/AgenciesTable.jsx create mode 100644 src/js/containers/agencyLanding/AgencyLandingContainer.jsx create mode 100644 src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx delete mode 100644 src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx delete mode 100644 src/js/containers/agencyProfiles/AgenciesTableContainer.jsx create mode 100644 src/js/dataMapping/agencyLanding/agenciesTableFields.js create mode 100644 src/js/helpers/agencyLandingHelper.js create mode 100644 src/js/redux/actions/agencyLanding/agencyLandingActions.js create mode 100644 src/js/redux/reducers/agencyLanding/agencyLandingReducer.js diff --git a/src/_scss/custom.scss b/src/_scss/custom.scss index 9f570fab43..06607d3185 100644 --- a/src/_scss/custom.scss +++ b/src/_scss/custom.scss @@ -13,6 +13,6 @@ @import './pages/glossary/glossaryPage'; @import './layouts/article/aboutArticle'; @import './pages/testStyle/testStyle'; -@import './pages/agencyProfiles/agencyProfiles'; +@import './pages/agencyLanding/agencyLandingPage'; // ***** MODALS @import './pages/modals/all'; diff --git a/src/_scss/pages/agencyLanding/agencyLandingPage.scss b/src/_scss/pages/agencyLanding/agencyLandingPage.scss new file mode 100644 index 0000000000..d7f8cf0ae1 --- /dev/null +++ b/src/_scss/pages/agencyLanding/agencyLandingPage.scss @@ -0,0 +1,30 @@ +.usa-da-agency-landing { + @import "layouts/summary/summary"; + @import "mixins/fullSectionWrap"; + @import "./header/header"; + @import './agencyLandingSearch'; + @import './table/table'; + + .agency-landing-content { + padding: ($global-pad * 2) 0; + .agency-landing-overview { + @include span-columns(12); + @include shift(2); + text-align: center; + h3 { + margin-top: 0; + } + } + .agency-landing-container { + .agency-landing-section { + @include fullSectionWrap(0,0); + &.results-count { + font-style: italic; + padding: rem(20) 0; + } + } + @include agencyLandingSearch; + @include agencyLandingTable; + } + } +} \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/agencyLandingSearch.scss b/src/_scss/pages/agencyLanding/agencyLandingSearch.scss new file mode 100644 index 0000000000..3efd40a4ac --- /dev/null +++ b/src/_scss/pages/agencyLanding/agencyLandingSearch.scss @@ -0,0 +1,36 @@ +@mixin agencyLandingSearch { + .agency-landing-search { + @include span-columns(16); + background-color: $color-primary-alt-lightest; + padding: rem(30); + border: 1px solid $color-vis-lightest; + text-align: center; + form { + // TODO - Lizzie: add mobile styling + position: relative; + input.search-field { + color: $color-gray-light; + font-size: rem(28); + font-weight: 300; + line-height: rem(36); + padding: rem(15); + //width: rem(684); + width: 75%; + padding-right: rem(30); + } + .search-button { + position: absolute; + left: 80%; + top: rem(15); + + @include button-unstyled; + width: 36px; + height: 36px; + + svg { + fill: $color-gray-light; + } + } + } + } +} \ No newline at end of file diff --git a/src/_scss/pages/agencyProfiles/header/header.scss b/src/_scss/pages/agencyLanding/header/header.scss similarity index 100% rename from src/_scss/pages/agencyProfiles/header/header.scss rename to src/_scss/pages/agencyLanding/header/header.scss diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss new file mode 100644 index 0000000000..63a87144d4 --- /dev/null +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -0,0 +1,5 @@ +@mixin agencyLandingTable { + .agency-landing-table { + @include span-columns(16); + } +} \ No newline at end of file diff --git a/src/_scss/pages/agencyProfiles/agencyProfiles.scss b/src/_scss/pages/agencyProfiles/agencyProfiles.scss deleted file mode 100644 index 61282f5c62..0000000000 --- a/src/_scss/pages/agencyProfiles/agencyProfiles.scss +++ /dev/null @@ -1,15 +0,0 @@ -.usa-da-agency-profiles { - @import "layouts/summary/summary"; - - @import "./header/header"; - - .agency-profiles-content { - padding: ($global-pad * 2) rem(35); - .agency-profiles-overview { - text-align: center; - h3 { - margin-top: 0; - } - } - } -} \ No newline at end of file diff --git a/src/js/components/agencyLanding/AgencyLandingPage.jsx b/src/js/components/agencyLanding/AgencyLandingPage.jsx new file mode 100644 index 0000000000..ac28699ade --- /dev/null +++ b/src/js/components/agencyLanding/AgencyLandingPage.jsx @@ -0,0 +1,43 @@ +/** + * AgencyLandingPage.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +import { agencyLandingPageMetaTags } from 'helpers/metaTagHelper'; + +import MetaTags from '../sharedComponents/metaTags/MetaTags'; +import Header from '../sharedComponents/header/Header'; +import Footer from '../sharedComponents/Footer'; + +import AgencyLandingHeader from './header/AgencyLandingHeader'; +import AgencyLandingContainer from 'containers/agencyLanding/agencyLandingContainer'; + +export default class AgencyLandingPage extends React.Component { + render() { + return ( +
+ +
+ +
+
+
+

Find an Agency Profile.

+
Understand the current spending of agencies in our agency profiles.
+

Sixty-six federal agencies report data to USAspending.gov. These include the + 15 executive departments whose leaders sit on the President's Cabinet, as well + as small independent boards and commissions. They range in size from $700 billion + down to less than $200,000.

+
+ +
+
+
+
+ ); + } +} diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx new file mode 100644 index 0000000000..b29bc1f7e6 --- /dev/null +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -0,0 +1,79 @@ +/** + * AgencyLandingResultsSection.jsx + * Created by Lizzie Salita 7/11/17 + */ + +import React from 'react'; + +import AgencyLandingTable from './table/AgencyLandingTable'; +import ResultsTableMessage from 'components/search/table/ResultsTableMessage'; +import AgencyLandingHeaderCellContainer from 'containers/agencyLanding/table/AgencyLandingHeaderCellContainer'; + +const propTypes = { + inFlight: React.PropTypes.bool, + results: React.PropTypes.array, + columns: React.PropTypes.array +}; + +export default class AgencyLandingResultsSection extends React.Component { + constructor(props) { + super(props); + + this.state = { + tableWidth: 0 + }; + + this.setTableWidth = this.setTableWidth.bind(this); + } + componentDidMount() { + // set the initial table width + this.setTableWidth(); + // watch the window for size changes + window.addEventListener('resize', this.setTableWidth); + } + + componentWillUnmount() { + // stop watching for size changes + window.removeEventListener('resize', this.setTableWidth); + } + + setTableWidth() { + // subtract 2px from the width to account for the table borders (2 * 1px on each side) + const tableWidth = this.tableWidthController.clientWidth - 2; + this.setState({ tableWidth }); + } + + render() { + let loadingWrapper = ''; + let message = null; + if (this.props.inFlight) { + loadingWrapper = 'loading-table'; + message = ; + } + else if (this.props.results.length === 0) { + // no results + message = ; + } + + return ( +
+
+
{ + // this is an empty div that scales via CSS + // the results table width will follow this div's width + this.tableWidthController = div; + }} /> + +
+ {message} +
+ ); + } +} + +AgencyLandingResultsSection.propTypes = propTypes; diff --git a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx new file mode 100644 index 0000000000..c9b4fe4ced --- /dev/null +++ b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx @@ -0,0 +1,34 @@ +/** + * AgencyLandingSearchBar.jsx + * Created by Lizzie Salita 7/10/17 + */ + +import React from 'react'; + +import { Search } from 'components/sharedComponents/icons/Icons'; + +export default class AgencyLandingSearchBar extends React.Component { + constructor(props) { + super(props); + } + + render() { + return ( +
+
+ + +
+
+ ); + } +} + diff --git a/src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx b/src/js/components/agencyLanding/header/AgencyLandingHeader.jsx similarity index 72% rename from src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx rename to src/js/components/agencyLanding/header/AgencyLandingHeader.jsx index 3997fba9ef..52a9cf6f38 100644 --- a/src/js/components/agencyProfiles/header/AgencyProfilesHeader.jsx +++ b/src/js/components/agencyLanding/header/AgencyLandingHeader.jsx @@ -1,11 +1,11 @@ /** - * AgencyProfilesHeader.jsx - * Created by Lizzie Salita + * AgencyLandingHeader.jsx + * Created by Lizzie Salita 7/7/17 */ import React from 'react'; -export default class AgencyProfilesHeader extends React.Component { +export default class AgencyLandingHeader extends React.Component { render() { return (
diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx new file mode 100644 index 0000000000..d984b8c326 --- /dev/null +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -0,0 +1,143 @@ +/** + * AgencyLandingTable.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; + +import Immutable, { OrderedSet } from 'immutable'; + +import IBTable from 'components/sharedComponents/IBTable/IBTable'; + +import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableGenericCell'; + +const propTypes = { + results: React.PropTypes.array, + columns: React.PropTypes.array, + headerCellClass: React.PropTypes.func.isRequired, + visibleWidth: React.PropTypes.number +}; + +const rowHeight = 40; +// setting the table height to a partial row prevents double bottom borders and also clearly +// indicates when there's more data +const tableHeight = 12.5 * rowHeight; + +export default class AgencyLandingTable extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + yPos: 0, + xPos: 0, + dataHash: null + }; + + this.rowClassName = this.rowClassName.bind(this); + this.tableScrolled = this.tableScrolled.bind(this); + } + + shouldComponentUpdate(nextProps) { + return (nextProps.visibleWidth !== this.props.visibleWidth); + } + + tableScrolled(xPos, yPos) { + // determine the table position + const rowNumber = this.rowAtYPosition(yPos); + + if (rowNumber >= this.props.results.length) { + // we have reached the bottom of the table, load next page + this.props.loadNextPage(); + } + + // save the scroll position + this.setState({ xPos, yPos }); + } + + rowAtYPosition(yPos, returnTop = false) { + // determine the table position + let yPosition = yPos; + if (!returnTop) { + // return the bottom row + yPosition += tableHeight; + } + return Math.floor(yPosition / rowHeight); + } + + rowClassName(index) { + let evenOdd = 'odd'; + if ((index + 1) % 2 === 0) { + evenOdd = 'even'; + } + return `agency-landing-results-row-${evenOdd}`; + } + + prepareTable() { + let totalWidth = 0; + + const HeaderCell = this.props.headerCellClass; + + const columns = this.props.columns.map((column, i) => { + totalWidth += column.width; + const isLast = i === this.props.columns.length - 1; + let cellName = null; + cellName = (index) => ( + + ); + + return { + width: column.width, + name: column.columnName, + columnId: `${column.columnName}`, + rowClassName: this.rowClassName, + header: ( + + ), + cell: cellName + }; + }); + + return { + columns, + width: totalWidth + }; + } + + render() { + const calculatedValues = this.prepareTable(); + + let noResultsClass = ''; + if (this.props.results.length === 0) { + // remove duplicated bottom border + noResultsClass = ' no-results'; + } + + return ( +
+ +
+ ); + } +} + +AgencyLandingTable.propTypes = propTypes; diff --git a/src/js/components/agencyProfiles/AgencyProfiles.jsx b/src/js/components/agencyProfiles/AgencyProfiles.jsx deleted file mode 100644 index 0d3443122d..0000000000 --- a/src/js/components/agencyProfiles/AgencyProfiles.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * AgencyProfiles.jsx - * Created by Lizzie Salita 7/7/17 - */ - -import React from 'react'; - -import { agencyLandingPageMetaTags } from 'helpers/metaTagHelper'; - -import MetaTags from '../sharedComponents/metaTags/MetaTags'; -import Header from '../sharedComponents/header/Header'; -import Footer from '../sharedComponents/Footer'; - -import AgencyProfilesHeader from './header/AgencyProfilesHeader'; -import AgencyProfilesContent from './AgencyProfilesContent'; - -export default class AgencyProfiles extends React.Component { - render() { - return ( -
- -
- -
- -
-
-
- ); - } -} diff --git a/src/js/components/agencyProfiles/AgencyProfilesContent.jsx b/src/js/components/agencyProfiles/AgencyProfilesContent.jsx deleted file mode 100644 index b36fde3049..0000000000 --- a/src/js/components/agencyProfiles/AgencyProfilesContent.jsx +++ /dev/null @@ -1,28 +0,0 @@ -/** - * AgencyProfilesContent.jsx - * Created by Lizzie Salita 7/7/17 - */ - -import React from 'react'; - -import AgenciesSearchContainer from 'containers/agencyProfiles/AgenciesSearchContainer'; -import AgenciesTableContainer from 'containers/agencyProfiles/AgenciesTableContainer'; - -export default class AgencyProfilesContent extends React.Component { - render() { - return ( -
-
-

Find an Agency Profile.

-
Understand the current spending of agencies in our agency profiles.
-

Sixty-six federal agencies report data to USAspending.gov. These include the - 15 executive departments whose leaders sit on the President's Cabinet, as well - as small independent boards and commissions. They range in size from $700 billion - down to less than $200,000.

-
- - -
- ); - } -} diff --git a/src/js/components/agencyProfiles/ProfileSearch.jsx b/src/js/components/agencyProfiles/ProfileSearch.jsx deleted file mode 100644 index 50281b669d..0000000000 --- a/src/js/components/agencyProfiles/ProfileSearch.jsx +++ /dev/null @@ -1,17 +0,0 @@ -/** - * ProfileSearch.jsx - * Created by Lizzie Salita 7/7/17 - */ - -import React from 'react'; - -export default class ProfileSearch extends React.Component { - - render() { - return ( -
- Search Bar -
- ); - } -} diff --git a/src/js/components/agencyProfiles/table/AgenciesTable.jsx b/src/js/components/agencyProfiles/table/AgenciesTable.jsx deleted file mode 100644 index f07617c5a2..0000000000 --- a/src/js/components/agencyProfiles/table/AgenciesTable.jsx +++ /dev/null @@ -1,17 +0,0 @@ -/** - * AgenciesTable.jsx - * Created by Lizzie Salita 7/7/17 - */ - -import React from 'react'; - -export default class AgenciesTable extends React.Component { - - render() { - return ( -
- Table -
- ); - } -} diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx new file mode 100644 index 0000000000..08fa40415a --- /dev/null +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -0,0 +1,204 @@ +/** + * AgencyLandingContainer.jsx + * Created by Lizzie Salita 7/7/17 + */ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { isCancel } from 'axios'; +import Immutable, { OrderedSet } from 'immutable'; + +import { measureTableHeader } from 'helpers/textMeasurement'; + +import AgenciesTableFields from 'dataMapping/agencyLanding/agenciesTableFields'; +import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; +import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; +import AgencyLandingHelper from 'helpers/agencyLandingHelper'; + +import AgencyLandingSearchBar from 'components/agencyLanding/agencyLandingSearchBar'; +import AgencyLandingResultsSection from 'components/agencyLanding/agencyLandingResultsSection'; + +const propTypes = { + agencies: React.PropTypes.instanceOf(Immutable.OrderedSet), + agenciesOrder: React.PropTypes.object, + setAgencies: React.PropTypes.func, + //setAgenciesOrder: React.PropTypes.func, + activetFY: React.PropTypes.string +}; + +export class AgencyLandingContainer extends React.Component { + constructor(props) { + super(props); + + this.state = { + columns: [], + inFlight: false + }; + + this.agenciesRequest = null; + } + + componentDidMount() { + this.showColumns(); + } + + componentDidUpdate(prevProps) { + if (this.props.agenciesOrder !== prevProps.agenciesOrder) { + // table sort changed + this.fetchAgencies(); + } + } + + componentWillUnmount() { + if (this.agenciesRequest) { + this.agenciesRequest.cancel(); + } + } + + formatSort() { + let direction = ''; + if (this.props.agenciesOrder.direction === 'desc') { + direction = '-'; + } + + return `${direction}${this.props.agenciesOrder.field}`; + } + + showColumns() { + const columns = []; + let sortOrder = AgenciesTableFields.defaultSortDirection; + + AgenciesTableFields.order.forEach((col) => { + const column = { + columnName: col, + displayName: AgenciesTableFields[col], + width: measureTableHeader(AgenciesTableFields[col]), + defaultDirection: sortOrder[col] + }; + columns.push(column); + }); + + this.setState({ + columns + }, () => { + this.fetchAgencies(); + }); + } + + fetchAgencies() { + // TODO - Lizzie: uncomment when endpoint is ready + //if (this.agenciesRequest) { + // // a request is in-flight, cancel it + // this.agenciesRequest.cancel(); + //} + // + //this.setState({ + // inFlight: true + //}); + // + //// generate the params + //const params = { + // filters: [ + // { + // field: 'actice_fy', + // operation: 'equals', + // value: this.props.activeFY + // } + // ], + // order: [this.formatSort()] + //}; + // + //this.agenciesRequest = AgencyLandingHelper.fetchAllAgencies(params); + // + //this.agenciesRequest.promise + // .then((res) => { + // this.setState({ + // inFlight: false + // }); + // + // this.parseAgencies(res.data); + // }) + // .catch((err) => { + // this.agenciesRequest = null; + // if (!isCancel(err)) { + // this.setState({ + // inFlight: false + // }); + // console.log(err); + // } + // }); + + const mockRes = {"results": [ + { + "id": 10, + "percentage_of_total_budget_authority": ".0567", + "agency_name": "Architect of the Capitol", + "budget_authority_amount": "4322852976.48", + "active_fy": "2017" + }, + { + "id": 11, + "percentage_of_total_budget_authority": ".00411", + "agency_name": "Library of Congress", + "budget_authority_amount": "9842852976.48", + "active_fy": "2017" + }, + { + "id": 14, + "percentage_of_total_budget_authority": ".00032", + "agency_name": "Government Publishing Office", + "budget_authority_amount": "1426852976.48", + "active_fy": "2017" + } + ]}; + this.parseAgencies(mockRes); + + } + + parseAgencies(data) { + const agencies = []; + data.results.forEach((item) => { + const agency = new Agency(item); + agencies.push(agency); + }); + + console.log(`agencies: ${agencies}`); + + this.props.setAgencies(agencies); + } + + render() { + // TODO - Lizzie: remove static value and use metadata + const resultsCount = 65; + + return ( +
+
+
+ +
+
+
+ {resultsCount} results +
+
+ +
+
+ ); + } +} + +AgencyLandingContainer.propTypes = propTypes; + +export default connect( + (state) => ({ + agencies: state.agencyLanding.agencies, + agenciesOrder: state.agencyLanding.agenciesOrder + }), + (dispatch) => bindActionCreators(agencyLandingActions, dispatch) +)(AgencyLandingContainer); diff --git a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx new file mode 100644 index 0000000000..ba316b1ebd --- /dev/null +++ b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx @@ -0,0 +1,56 @@ +/** + * AgencyLandingHeaderCellContainer.jsx + * Created by Lizzie Salita 7/11/17 + */ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; + +// just import the two relevant actions +import { setAgenciesOrder, resetAgenciesOrder } from 'redux/actions/agencyLanding/agencyLandingActions'; + +import ResultsTableHeaderCell from 'components/search/table/cells/ResultsTableHeaderCell'; + +// combine the action functions into an object for the react-redux bindings +const actions = { + setAgenciesOrder, + resetAgenciesOrder +}; + +const propTypes = { + setAgenciesOrder: React.PropTypes.func, + order: React.PropTypes.object +}; + +class AgencyLandingHeaderCellContainer extends React.Component { + constructor(props) { + super(props); + + this.setAgenciesOrder = this.setAgenciesOrder.bind(this); + } + + setAgenciesOrder(field, direction) { + this.props.setAgenciesOrder({ + field, + direction + }); + } + + render() { + return ( + + ); + } +} + +AgencyLandingHeaderCellContainer.propTypes = propTypes; + +export default connect( + (state) => ({ + order: state.agencyLanding.agenciesOrder + }), + (dispatch) => bindActionCreators(actions, dispatch) +)(AgencyLandingHeaderCellContainer); diff --git a/src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx b/src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx deleted file mode 100644 index ea205f17ac..0000000000 --- a/src/js/containers/agencyProfiles/AgenciesSearchContainer.jsx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * AgenciesSearchContainer.jsx - * Created by Lizzie Salita 7/7/17 - */ - -import React from 'react'; - -import ProfileSearch from 'components/agencyProfiles/ProfileSearch'; - -export default class AgenciesSearchContainer extends React.Component { - render() { - return ( - - ); - } -} diff --git a/src/js/containers/agencyProfiles/AgenciesTableContainer.jsx b/src/js/containers/agencyProfiles/AgenciesTableContainer.jsx deleted file mode 100644 index aa37ad1713..0000000000 --- a/src/js/containers/agencyProfiles/AgenciesTableContainer.jsx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * AgenciesTableContainer.jsx - * Created by Lizzie Salita 7/7/17 - */ - -import React from 'react'; - -import AgenciesTable from 'components/agencyProfiles/table/AgenciesTable'; - -export default class AgenciesTableContainer extends React.Component { - render() { - return ( - - ); - } -} diff --git a/src/js/containers/router/RouterRoutes.jsx b/src/js/containers/router/RouterRoutes.jsx index bf608ddfa8..61c5b0c9ac 100644 --- a/src/js/containers/router/RouterRoutes.jsx +++ b/src/js/containers/router/RouterRoutes.jsx @@ -142,7 +142,7 @@ const routes = { parent: '/agencyprofiles', component: (cb) => { require.ensure([], (require) => { - cb(require('components/agencyProfiles/AgencyProfiles').default); + cb(require('components/agencyLanding/AgencyLandingPage').default); }); } } diff --git a/src/js/dataMapping/agencyLanding/agenciesTableFields.js b/src/js/dataMapping/agencyLanding/agenciesTableFields.js new file mode 100644 index 0000000000..1094cb21f8 --- /dev/null +++ b/src/js/dataMapping/agencyLanding/agenciesTableFields.js @@ -0,0 +1,18 @@ +const agenciesTableFields = { + defaultSortDirection: { + agency_name: 'desc', + budget_authority_amount: 'desc', + percentage_of_total_budget_authority: 'desc' + }, + defaultSortField: 'agency_name', + order: [ + 'agency_name', + 'budget_authority_amount', + 'percentage_of_total_budget_authority' + ], + agency_name: 'Agency Name', + budget_authority_amount: 'Budget Authority', + percentage_of_total_budget_authority: 'Percent of Total U.S. Budget' +}; + +export default agenciesTableFields; diff --git a/src/js/helpers/agencyLandingHelper.js b/src/js/helpers/agencyLandingHelper.js new file mode 100644 index 0000000000..b9830a39f7 --- /dev/null +++ b/src/js/helpers/agencyLandingHelper.js @@ -0,0 +1,41 @@ +/** + * agencyLandingHelper.js + * Created by Lizzie Salita 7/10/17 + **/ + +import Axios, { CancelToken } from 'axios'; + +import kGlobalConstants from 'GlobalConstants'; + +// TODO - Lizzie: update when endpoint is ready +export const fetchAllAgencies = (params) => { + const source = CancelToken.source(); + return { + promise: Axios.request({ + url: 'v2/references/agency/', + baseURL: kGlobalConstants.API, + method: 'post', + data: params, + cancelToken: source.token + }), + cancel() { + source.cancel(); + } + }; +}; + +export const fetchSearchResults = (params) => { + const source = CancelToken.source(); + return { + promise: Axios.request({ + url: 'v1/references/agency/autocomplete/', + baseURL: kGlobalConstants.API, + method: 'post', + data: params, + cancelToken: source.token + }), + cancel() { + source.cancel(); + } + }; +}; diff --git a/src/js/helpers/glossaryHelper.js b/src/js/helpers/glossaryHelper.js index eb620221c4..e3b446212f 100644 --- a/src/js/helpers/glossaryHelper.js +++ b/src/js/helpers/glossaryHelper.js @@ -1,5 +1,5 @@ /** - * guideHelper.js + * glossaryHelper.js * Created by Kevin Li 5/3/17 **/ diff --git a/src/js/redux/actions/agencyLanding/agencyLandingActions.js b/src/js/redux/actions/agencyLanding/agencyLandingActions.js new file mode 100644 index 0000000000..4b71ccbe1c --- /dev/null +++ b/src/js/redux/actions/agencyLanding/agencyLandingActions.js @@ -0,0 +1,18 @@ +/** + * agencyLandingActions.js + * Created by Lizzie Salita 7/10/17 + */ + +export const setAgencies = (state) => ({ + type: 'SET_AGENCIES', + agencies: state +}); + +export const setAgenciesOrder = (state) => ({ + type: 'SET_AGENCIES_ORDER', + order: state +}); + +export const resetAgenciesOrder = () => ({ + type: 'RESET_AGENCIES_ORDER' +}); \ No newline at end of file diff --git a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js new file mode 100644 index 0000000000..723450ca08 --- /dev/null +++ b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js @@ -0,0 +1,47 @@ +/** + * agencyLandingReducer.js + * Created by Lizzie Salita 7/10/17 + */ + +import { Record, OrderedSet } from 'immutable'; + +export const Agency = Record({ + id: '', + agency_name: '', + budget_authority_amount: '', + percentage_of_total_budget_authority: '' +}); + +const initialState = { + agencies: new OrderedSet(), + agenciesOrder: { + field: 'agency_name', + direction: 'desc' + } +}; + + +const agencyLandingReducer = (state = initialState, action) => { + switch (action.type) { + case 'SET_AGENCIES': { + return Object.assign({}, state, { + agencies: new OrderedSet(action.agencies) + }); + } + case 'SET_AGENCIES_ORDER': { + const order = Object.assign({}, state.agenciesOrder, action.order); + + return Object.assign({}, state, { + agenciesOrder: order + }); + } + case 'RESET_SEARCH_ORDER': { + // TODO - Lizzie + return state; + } + default: + return state; + } +}; + +export default agencyLandingReducer; diff --git a/src/js/redux/reducers/index.js b/src/js/redux/reducers/index.js index f6008fa95e..abd2a23482 100644 --- a/src/js/redux/reducers/index.js +++ b/src/js/redux/reducers/index.js @@ -20,6 +20,7 @@ import awardReducer from './award/awardReducer'; import accountReducer from './account/accountReducer'; import agencyReducer from './agency/agencyReducer'; import glossaryReducer from './glossary/glossaryReducer'; +import agencyLandingReducer from './agencyLanding/agencyLandingReducer'; const appReducer = combineReducers({ resultsMeta: resultsMetaReducer, @@ -36,7 +37,8 @@ const appReducer = combineReducers({ autocompleteBudgetCategories: budgetCategoryReducer, account: accountReducer, agency: agencyReducer, - glossary: glossaryReducer + glossary: glossaryReducer, + agencyLanding: agencyLandingReducer }); export default appReducer; From 644023a784e0288fc30659841947055bdc0f9b96 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Wed, 12 Jul 2017 18:14:13 -0400 Subject: [PATCH 09/97] lint fixes --- .../agencyLanding/AgencyLandingPage.jsx | 9 ++- .../AgencyLandingResultsSection.jsx | 2 +- .../agencyLanding/AgencyLandingSearchBar.jsx | 6 +- .../table/AgencyLandingTable.jsx | 10 --- .../agencyLanding/AgencyLandingContainer.jsx | 72 +++++++++---------- .../agencyLanding/agencyLandingActions.js | 2 +- 6 files changed, 43 insertions(+), 58 deletions(-) diff --git a/src/js/components/agencyLanding/AgencyLandingPage.jsx b/src/js/components/agencyLanding/AgencyLandingPage.jsx index ac28699ade..df18cc7143 100644 --- a/src/js/components/agencyLanding/AgencyLandingPage.jsx +++ b/src/js/components/agencyLanding/AgencyLandingPage.jsx @@ -7,12 +7,11 @@ import React from 'react'; import { agencyLandingPageMetaTags } from 'helpers/metaTagHelper'; -import MetaTags from '../sharedComponents/metaTags/MetaTags'; -import Header from '../sharedComponents/header/Header'; -import Footer from '../sharedComponents/Footer'; - +import MetaTags from 'components/sharedComponents/metaTags/MetaTags'; +import Header from 'components/sharedComponents/header/Header'; +import Footer from 'components/sharedComponents/Footer'; +import AgencyLandingContainer from 'containers/agencyLanding/AgencyLandingContainer'; import AgencyLandingHeader from './header/AgencyLandingHeader'; -import AgencyLandingContainer from 'containers/agencyLanding/agencyLandingContainer'; export default class AgencyLandingPage extends React.Component { render() { diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx index b29bc1f7e6..bc5d260e78 100644 --- a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -5,9 +5,9 @@ import React from 'react'; -import AgencyLandingTable from './table/AgencyLandingTable'; import ResultsTableMessage from 'components/search/table/ResultsTableMessage'; import AgencyLandingHeaderCellContainer from 'containers/agencyLanding/table/AgencyLandingHeaderCellContainer'; +import AgencyLandingTable from './table/AgencyLandingTable'; const propTypes = { inFlight: React.PropTypes.bool, diff --git a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx index c9b4fe4ced..042c2acb84 100644 --- a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx +++ b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx @@ -8,9 +8,9 @@ import React from 'react'; import { Search } from 'components/sharedComponents/icons/Icons'; export default class AgencyLandingSearchBar extends React.Component { - constructor(props) { - super(props); - } + // constructor(props) { + // super(props); + // } render() { return ( diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index d984b8c326..fc7be0c787 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -5,8 +5,6 @@ import React from 'react'; -import Immutable, { OrderedSet } from 'immutable'; - import IBTable from 'components/sharedComponents/IBTable/IBTable'; import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableGenericCell'; @@ -42,14 +40,6 @@ export default class AgencyLandingTable extends React.PureComponent { } tableScrolled(xPos, yPos) { - // determine the table position - const rowNumber = this.rowAtYPosition(yPos); - - if (rowNumber >= this.props.results.length) { - // we have reached the bottom of the table, load next page - this.props.loadNextPage(); - } - // save the scroll position this.setState({ xPos, yPos }); } diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 08fa40415a..924f2d5434 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -6,25 +6,23 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { isCancel } from 'axios'; -import Immutable, { OrderedSet } from 'immutable'; +// import { isCancel } from 'axios'; +import Immutable from 'immutable'; import { measureTableHeader } from 'helpers/textMeasurement'; import AgenciesTableFields from 'dataMapping/agencyLanding/agenciesTableFields'; import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; -import AgencyLandingHelper from 'helpers/agencyLandingHelper'; +// import AgencyLandingHelper from 'helpers/agencyLandingHelper'; -import AgencyLandingSearchBar from 'components/agencyLanding/agencyLandingSearchBar'; -import AgencyLandingResultsSection from 'components/agencyLanding/agencyLandingResultsSection'; +import AgencyLandingSearchBar from 'components/agencyLanding/AgencyLandingSearchBar'; +import AgencyLandingResultsSection from 'components/agencyLanding/AgencyLandingResultsSection'; const propTypes = { agencies: React.PropTypes.instanceOf(Immutable.OrderedSet), agenciesOrder: React.PropTypes.object, - setAgencies: React.PropTypes.func, - //setAgenciesOrder: React.PropTypes.func, - activetFY: React.PropTypes.string + setAgencies: React.PropTypes.func }; export class AgencyLandingContainer extends React.Component { @@ -67,7 +65,7 @@ export class AgencyLandingContainer extends React.Component { showColumns() { const columns = []; - let sortOrder = AgenciesTableFields.defaultSortDirection; + const sortOrder = AgenciesTableFields.defaultSortDirection; AgenciesTableFields.order.forEach((col) => { const column = { @@ -88,17 +86,17 @@ export class AgencyLandingContainer extends React.Component { fetchAgencies() { // TODO - Lizzie: uncomment when endpoint is ready - //if (this.agenciesRequest) { + // if (this.agenciesRequest) { // // a request is in-flight, cancel it // this.agenciesRequest.cancel(); - //} + // } // - //this.setState({ + // this.setState({ // inFlight: true - //}); + // }); // - //// generate the params - //const params = { + // // generate the params + // const params = { // filters: [ // { // field: 'actice_fy', @@ -107,11 +105,11 @@ export class AgencyLandingContainer extends React.Component { // } // ], // order: [this.formatSort()] - //}; + // }; // - //this.agenciesRequest = AgencyLandingHelper.fetchAllAgencies(params); + // this.agenciesRequest = AgencyLandingHelper.fetchAllAgencies(params); // - //this.agenciesRequest.promise + // this.agenciesRequest.promise // .then((res) => { // this.setState({ // inFlight: false @@ -129,31 +127,31 @@ export class AgencyLandingContainer extends React.Component { // } // }); - const mockRes = {"results": [ + const mockRes = { results: [ { - "id": 10, - "percentage_of_total_budget_authority": ".0567", - "agency_name": "Architect of the Capitol", - "budget_authority_amount": "4322852976.48", - "active_fy": "2017" + id: 10, + percentage_of_total_budget_authority: ".0567", + agency_name: "Architect of the Capitol", + budget_authority_amount: "4322852976.48", + active_fy: "2017" }, { - "id": 11, - "percentage_of_total_budget_authority": ".00411", - "agency_name": "Library of Congress", - "budget_authority_amount": "9842852976.48", - "active_fy": "2017" + id: 11, + percentage_of_total_budget_authority: ".00411", + agency_name: "Library of Congress", + budget_authority_amount: "9842852976.48", + active_fy: "2017" }, { - "id": 14, - "percentage_of_total_budget_authority": ".00032", - "agency_name": "Government Publishing Office", - "budget_authority_amount": "1426852976.48", - "active_fy": "2017" + id: 14, + percentage_of_total_budget_authority: ".00032", + agency_name: "Government Publishing Office", + budget_authority_amount: "1426852976.48", + active_fy: "2017" } - ]}; - this.parseAgencies(mockRes); + ] }; + this.parseAgencies(mockRes); } parseAgencies(data) { @@ -163,8 +161,6 @@ export class AgencyLandingContainer extends React.Component { agencies.push(agency); }); - console.log(`agencies: ${agencies}`); - this.props.setAgencies(agencies); } diff --git a/src/js/redux/actions/agencyLanding/agencyLandingActions.js b/src/js/redux/actions/agencyLanding/agencyLandingActions.js index 4b71ccbe1c..836754d4e2 100644 --- a/src/js/redux/actions/agencyLanding/agencyLandingActions.js +++ b/src/js/redux/actions/agencyLanding/agencyLandingActions.js @@ -15,4 +15,4 @@ export const setAgenciesOrder = (state) => ({ export const resetAgenciesOrder = () => ({ type: 'RESET_AGENCIES_ORDER' -}); \ No newline at end of file +}); From 1ed15a747fc3eb55234d770daa93fc41f2d0e24c Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 13 Jul 2017 12:01:33 -0400 Subject: [PATCH 10/97] Updated route, sass indentation, and table styling --- .../agencyLanding/agencyLandingPage.scss | 50 ++++++++-------- .../agencyLanding/agencyLandingSearch.scss | 59 +++++++++---------- .../agencyLanding/table/resultsSection.scss | 29 +++++++++ .../pages/agencyLanding/table/table.scss | 34 +++++++++-- .../AgencyLandingResultsSection.jsx | 4 +- src/js/containers/router/RouterRoutes.jsx | 4 +- 6 files changed, 117 insertions(+), 63 deletions(-) create mode 100644 src/_scss/pages/agencyLanding/table/resultsSection.scss diff --git a/src/_scss/pages/agencyLanding/agencyLandingPage.scss b/src/_scss/pages/agencyLanding/agencyLandingPage.scss index d7f8cf0ae1..a208d4c6fe 100644 --- a/src/_scss/pages/agencyLanding/agencyLandingPage.scss +++ b/src/_scss/pages/agencyLanding/agencyLandingPage.scss @@ -1,30 +1,30 @@ .usa-da-agency-landing { - @import "layouts/summary/summary"; - @import "mixins/fullSectionWrap"; - @import "./header/header"; - @import './agencyLandingSearch'; - @import './table/table'; + @import "layouts/summary/summary"; + @import "mixins/fullSectionWrap"; + @import "./header/header"; + @import './agencyLandingSearch'; + @import './table/resultsSection'; - .agency-landing-content { - padding: ($global-pad * 2) 0; - .agency-landing-overview { - @include span-columns(12); - @include shift(2); - text-align: center; - h3 { - margin-top: 0; - } - } - .agency-landing-container { - .agency-landing-section { - @include fullSectionWrap(0,0); - &.results-count { - font-style: italic; - padding: rem(20) 0; + .agency-landing-content { + padding: ($global-pad * 2) 0; + .agency-landing-overview { + @include span-columns(12); + @include shift(2); + text-align: center; + h3 { + margin-top: 0; + } + } + .agency-landing-container { + .agency-landing-section { + @include fullSectionWrap(0,0); + &.results-count { + font-style: italic; + padding: rem(20) 0; + } + } + @include agencyLandingSearch; + @include resultsSection; } - } - @include agencyLandingSearch; - @include agencyLandingTable; } - } } \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/agencyLandingSearch.scss b/src/_scss/pages/agencyLanding/agencyLandingSearch.scss index 3efd40a4ac..b277ab836a 100644 --- a/src/_scss/pages/agencyLanding/agencyLandingSearch.scss +++ b/src/_scss/pages/agencyLanding/agencyLandingSearch.scss @@ -1,36 +1,35 @@ @mixin agencyLandingSearch { - .agency-landing-search { - @include span-columns(16); - background-color: $color-primary-alt-lightest; - padding: rem(30); - border: 1px solid $color-vis-lightest; - text-align: center; - form { - // TODO - Lizzie: add mobile styling - position: relative; - input.search-field { - color: $color-gray-light; - font-size: rem(28); - font-weight: 300; - line-height: rem(36); - padding: rem(15); - //width: rem(684); - width: 75%; - padding-right: rem(30); - } - .search-button { - position: absolute; - left: 80%; - top: rem(15); + .agency-landing-search { + @include span-columns(16); + background-color: $color-primary-alt-lightest; + padding: rem(30); + border: 1px solid $color-vis-lightest; + text-align: center; + form { + // TODO - Lizzie: add mobile styling + position: relative; + input.search-field { + color: $color-gray-light; + font-size: rem(28); + font-weight: 300; + line-height: rem(36); + padding: rem(15); + width: 75%; + padding-right: rem(30); + } + .search-button { + position: absolute; + left: 80%; + top: rem(15); - @include button-unstyled; - width: 36px; - height: 36px; + @include button-unstyled; + width: 36px; + height: 36px; - svg { - fill: $color-gray-light; + svg { + fill: $color-gray-light; + } + } } - } } - } } \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/table/resultsSection.scss b/src/_scss/pages/agencyLanding/table/resultsSection.scss new file mode 100644 index 0000000000..cf979a04d1 --- /dev/null +++ b/src/_scss/pages/agencyLanding/table/resultsSection.scss @@ -0,0 +1,29 @@ +@mixin resultsSection { + .agency-landing-results { + transition: opacity 0.25s ease; + margin-top: ($global-mrg * 4); + + @import './table'; + + .loading-table { + opacity: 0.5; + @include transition(opacity 0.25s ease-in); + } + + .loaded-table { + opacity: 1; + @include transition(opacity 0.25s ease-in); + } + + .agency-landing-table-width-master { + width: 100%; + } + + .results-table-message { + margin-top: 1rem; + font-size: $small-font-size; + color: $color-base; + text-align: center; + } + } +} diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss index 63a87144d4..3fe5d55b85 100644 --- a/src/_scss/pages/agencyLanding/table/table.scss +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -1,5 +1,31 @@ -@mixin agencyLandingTable { - .agency-landing-table { - @include span-columns(16); - } +.agency-landing-results-table { + // implement the library style + @import '../../../lib/ibTable/ibTable'; + margin-top: rem(15); + display: block; + border: 1px solid $color-gray-light; + // placeholder background for when the user scrolls really fast + background: repeating-linear-gradient( $color-white, $color-white 40px, $color-gray-lightest 40px, $color-gray-lightest 80px); + &.no-results { + border-bottom: none; + } + .award-result-generic-cell { + @import "../../search/results/table/cells/_genericCell"; + @include genericCell(); + } + .award-result-header-cell { + @import "../../search/results/table/cells/_genericHeader"; + @include genericHeader(); + &.last-column { + border-right: none; + } + } + // gray out even rows + .row-even { + background-color: #f7f7f7; + } + // override the header style for a bottom border + .ibt-header { + border-bottom: 1px solid #ADAFB4; + } } \ No newline at end of file diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx index bc5d260e78..0b7c8e36fe 100644 --- a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -56,10 +56,10 @@ export default class AgencyLandingResultsSection extends React.Component { } return ( -
+
{ // this is an empty div that scales via CSS // the results table width will follow this div's width diff --git a/src/js/containers/router/RouterRoutes.jsx b/src/js/containers/router/RouterRoutes.jsx index 61c5b0c9ac..1c93879706 100644 --- a/src/js/containers/router/RouterRoutes.jsx +++ b/src/js/containers/router/RouterRoutes.jsx @@ -138,8 +138,8 @@ const routes = { } }, { - path: '/agencyprofiles', - parent: '/agencyprofiles', + path: '/agency', + parent: '/agency', component: (cb) => { require.ensure([], (require) => { cb(require('components/agencyLanding/AgencyLandingPage').default); From 36640fa6e7ea2ee7395e8e87033c3d19f02080d9 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 13 Jul 2017 12:40:04 -0400 Subject: [PATCH 11/97] Agencies table styling --- .../table/cells/_agencyLandingCell.scss | 11 ++++ .../table/cells/_agencyLandingHeaderCell.scss | 50 +++++++++++++++++++ .../agencyLanding/table/resultsSection.scss | 1 - .../pages/agencyLanding/table/table.scss | 15 +++--- 4 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss create mode 100644 src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss diff --git a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss new file mode 100644 index 0000000000..c91886cdca --- /dev/null +++ b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss @@ -0,0 +1,11 @@ +@mixin agencyLandingCell() { + .cell-content { + padding: rem(12) rem(16); + font-size: rem(12); + color: $color-base; + box-sizing: border-box; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss new file mode 100644 index 0000000000..d7481752d8 --- /dev/null +++ b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss @@ -0,0 +1,50 @@ +@mixin agencyLandingHeader() { + + .cell-content { + //background-color: $color-gray; + white-space: normal; + font-weight: 600; + font-size: rem(14); + line-height: rem(28); + color: $color-base; + cursor: pointer; + + .header-sort { + display: table; + padding: rem(11) rem(20); + + .header-label { + display: table-cell; + vertical-align: middle; + } + + .header-icons { + display: table-cell; + vertical-align: middle; + padding-left: rem(5); + height: rem(10); + + .sort-icon { + @include button-unstyled; + display: block; + line-height: rem(10); + width: rem(14); + height: rem(10); + text-align: center; + + svg { + fill: #86888E; + height: rem(11); + width: rem(11); + } + + &.active { + svg { + fill: $color-active; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/table/resultsSection.scss b/src/_scss/pages/agencyLanding/table/resultsSection.scss index cf979a04d1..78a9ee8075 100644 --- a/src/_scss/pages/agencyLanding/table/resultsSection.scss +++ b/src/_scss/pages/agencyLanding/table/resultsSection.scss @@ -1,7 +1,6 @@ @mixin resultsSection { .agency-landing-results { transition: opacity 0.25s ease; - margin-top: ($global-mrg * 4); @import './table'; diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss index 3fe5d55b85..c311b6b036 100644 --- a/src/_scss/pages/agencyLanding/table/table.scss +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -7,18 +7,15 @@ // placeholder background for when the user scrolls really fast background: repeating-linear-gradient( $color-white, $color-white 40px, $color-gray-lightest 40px, $color-gray-lightest 80px); &.no-results { - border-bottom: none; + border: none; } .award-result-generic-cell { - @import "../../search/results/table/cells/_genericCell"; - @include genericCell(); + @import "./cells/_agencyLandingCell"; + @include agencyLandingCell(); } .award-result-header-cell { - @import "../../search/results/table/cells/_genericHeader"; - @include genericHeader(); - &.last-column { - border-right: none; - } + @import "./cells/_agencyLandingHeaderCell"; + @include agencyLandingHeader(); } // gray out even rows .row-even { @@ -26,6 +23,6 @@ } // override the header style for a bottom border .ibt-header { - border-bottom: 1px solid #ADAFB4; + //border-bottom: 1px solid #ADAFB4; } } \ No newline at end of file From 455d3fad23361c4d5b7eb5129b6e95a76283842c Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 13 Jul 2017 15:51:09 -0400 Subject: [PATCH 12/97] Format data for the table; added batch metadata --- .../table/AgencyLandingTable.jsx | 11 ++++- .../agencyLanding/AgencyLandingContainer.jsx | 44 ++++++++++++++----- .../agencyLanding/agenciesTableFields.js | 6 +-- .../agencyLanding/agencyLandingActions.js | 4 -- .../agencyLanding/agencyLandingReducer.js | 23 +++++++--- 5 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index fc7be0c787..1b5d97bd92 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -4,12 +4,14 @@ */ import React from 'react'; +import Immutable from 'immutable'; import IBTable from 'components/sharedComponents/IBTable/IBTable'; import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableGenericCell'; const propTypes = { + batch: React.PropTypes.object, results: React.PropTypes.array, columns: React.PropTypes.array, headerCellClass: React.PropTypes.func.isRequired, @@ -36,7 +38,14 @@ export default class AgencyLandingTable extends React.PureComponent { } shouldComponentUpdate(nextProps) { - return (nextProps.visibleWidth !== this.props.visibleWidth); + if (!Immutable.is(nextProps.batch, this.props.batch)) { + return true; + } + else if (nextProps.visibleWidth !== this.props.visibleWidth) { + // re-render if the window size changed + return true; + } + return false; } tableScrolled(xPos, yPos) { diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 924f2d5434..5bd53b7062 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -22,7 +22,8 @@ import AgencyLandingResultsSection from 'components/agencyLanding/AgencyLandingR const propTypes = { agencies: React.PropTypes.instanceOf(Immutable.OrderedSet), agenciesOrder: React.PropTypes.object, - setAgencies: React.PropTypes.func + setAgencies: React.PropTypes.func, + meta: React.PropTypes.object }; export class AgencyLandingContainer extends React.Component { @@ -129,22 +130,22 @@ export class AgencyLandingContainer extends React.Component { const mockRes = { results: [ { - id: 10, - percentage_of_total_budget_authority: ".0567", + agency_id: 10, + percentage_of_total_budget_authority: ".0467", agency_name: "Architect of the Capitol", - budget_authority_amount: "4322852976.48", + budget_authority_amount: "322852976.48", active_fy: "2017" }, { - id: 11, + agency_id: 11, percentage_of_total_budget_authority: ".00411", agency_name: "Library of Congress", budget_authority_amount: "9842852976.48", active_fy: "2017" }, { - id: 14, - percentage_of_total_budget_authority: ".00032", + agency_id: 14, + percentage_of_total_budget_authority: ".032", agency_name: "Government Publishing Office", budget_authority_amount: "1426852976.48", active_fy: "2017" @@ -157,7 +158,28 @@ export class AgencyLandingContainer extends React.Component { parseAgencies(data) { const agencies = []; data.results.forEach((item) => { - const agency = new Agency(item); + // Create a link to the agency's profile page + const link = ( + {item.agency_name} + ); + + // Round to 2 decimal places and don't show 0.00 + let percent = Math.round(parseFloat(item.percentage_of_total_budget_authority)*100)/100; + + if (percent == 0.00) { + percent = 'Less than 0.01%'; + } + else { + percent = `${percent}%`; + } + + const agencyObject = { + agency_profile_link: link, + budget_authority_amount: item.budget_authority_amount, + percentage_of_total_budget_authority: percent + }; + + const agency = new Agency(agencyObject); agencies.push(agency); }); @@ -165,7 +187,7 @@ export class AgencyLandingContainer extends React.Component { } render() { - // TODO - Lizzie: remove static value and use metadata + // TODO - Lizzie: remove static value const resultsCount = 65; return ( @@ -180,6 +202,7 @@ export class AgencyLandingContainer extends React.Component {
@@ -194,7 +217,8 @@ AgencyLandingContainer.propTypes = propTypes; export default connect( (state) => ({ agencies: state.agencyLanding.agencies, - agenciesOrder: state.agencyLanding.agenciesOrder + agenciesOrder: state.agencyLanding.agenciesOrder, + meta: state.agencyLanding.agenciesMeta }), (dispatch) => bindActionCreators(agencyLandingActions, dispatch) )(AgencyLandingContainer); diff --git a/src/js/dataMapping/agencyLanding/agenciesTableFields.js b/src/js/dataMapping/agencyLanding/agenciesTableFields.js index 1094cb21f8..5e891704f3 100644 --- a/src/js/dataMapping/agencyLanding/agenciesTableFields.js +++ b/src/js/dataMapping/agencyLanding/agenciesTableFields.js @@ -1,16 +1,16 @@ const agenciesTableFields = { defaultSortDirection: { - agency_name: 'desc', + agency_profile_link: 'desc', budget_authority_amount: 'desc', percentage_of_total_budget_authority: 'desc' }, defaultSortField: 'agency_name', order: [ - 'agency_name', + 'agency_profile_link', 'budget_authority_amount', 'percentage_of_total_budget_authority' ], - agency_name: 'Agency Name', + agency_profile_link: 'Agency Name', budget_authority_amount: 'Budget Authority', percentage_of_total_budget_authority: 'Percent of Total U.S. Budget' }; diff --git a/src/js/redux/actions/agencyLanding/agencyLandingActions.js b/src/js/redux/actions/agencyLanding/agencyLandingActions.js index 836754d4e2..d5924d1b17 100644 --- a/src/js/redux/actions/agencyLanding/agencyLandingActions.js +++ b/src/js/redux/actions/agencyLanding/agencyLandingActions.js @@ -12,7 +12,3 @@ export const setAgenciesOrder = (state) => ({ type: 'SET_AGENCIES_ORDER', order: state }); - -export const resetAgenciesOrder = () => ({ - type: 'RESET_AGENCIES_ORDER' -}); diff --git a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js index 723450ca08..177e1adb0e 100644 --- a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js +++ b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js @@ -3,11 +3,11 @@ * Created by Lizzie Salita 7/10/17 */ +import { uniqueId } from 'lodash'; import { Record, OrderedSet } from 'immutable'; export const Agency = Record({ - id: '', - agency_name: '', + agency_profile_link: '', budget_authority_amount: '', percentage_of_total_budget_authority: '' }); @@ -17,6 +17,12 @@ const initialState = { agenciesOrder: { field: 'agency_name', direction: 'desc' + }, + agenciesMeta: { + batch: { + queryId: uniqueId(), + searchId: uniqueId() + } } }; @@ -24,8 +30,15 @@ const initialState = { const agencyLandingReducer = (state = initialState, action) => { switch (action.type) { case 'SET_AGENCIES': { + const meta = Object.assign({}, state.agenciesMeta, { + batch: { + queryId: uniqueId(), + searchId: uniqueId() + } + }); return Object.assign({}, state, { - agencies: new OrderedSet(action.agencies) + agencies: new OrderedSet(action.agencies), + agenciesMeta: meta }); } case 'SET_AGENCIES_ORDER': { @@ -35,10 +48,6 @@ const agencyLandingReducer = (state = initialState, action) => { agenciesOrder: order }); } - case 'RESET_SEARCH_ORDER': { - // TODO - Lizzie - return state; - } default: return state; } From 0c79178e3551ab1f9fb7af85846408aed589aae8 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 13 Jul 2017 16:03:09 -0400 Subject: [PATCH 13/97] Made a separate table cell component for agency profile link --- .../table/AgencyLandingTable.jsx | 33 +++++++++----- .../table/cells/AgencyLinkCell.jsx | 45 +++++++++++++++++++ .../agencyLanding/AgencyLandingContainer.jsx | 6 +-- 3 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 1b5d97bd92..396cf443e5 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -9,6 +9,7 @@ import Immutable from 'immutable'; import IBTable from 'components/sharedComponents/IBTable/IBTable'; import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableGenericCell'; +import AgencyLinkCell from './cells/AgencyLinkCell'; const propTypes = { batch: React.PropTypes.object, @@ -80,16 +81,28 @@ export default class AgencyLandingTable extends React.PureComponent { totalWidth += column.width; const isLast = i === this.props.columns.length - 1; let cellName = null; - cellName = (index) => ( - - ); - + if (column.columnName === 'agency_profile_link') { + cellName = (index) => ( + + ); + } + else { + cellName = (index) => ( + + ); + } return { width: column.width, name: column.columnName, diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx new file mode 100644 index 0000000000..775e2af62b --- /dev/null +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -0,0 +1,45 @@ +/** + * AgencyLinkCell.jsx + * Created by Lizzie Salita 7/13/17 + **/ + +import React from 'react'; + +const propTypes = { + data: React.PropTypes.object, + rowIndex: React.PropTypes.number, + column: React.PropTypes.string, + isLastColumn: React.PropTypes.bool +}; + +export default class AgencyLinkCell extends React.Component { + render() { + // cell needs to have some content or it will collapse + // replace with a   if there's no data + let content = this.props.data; + if (!content) { + content = "\u00A0"; + } + + // calculate even-odd class names + let rowClass = 'row-even'; + if (this.props.rowIndex % 2 === 0) { + // row index is zero-based + rowClass = 'row-odd'; + } + + if (this.props.isLastColumn) { + rowClass += ' last-column'; + } + + return ( +
+
+ {content} +
+
+ ); + } +} + +AgencyLinkCell.propTypes = propTypes; diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 5bd53b7062..09743a71d4 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -160,13 +160,13 @@ export class AgencyLandingContainer extends React.Component { data.results.forEach((item) => { // Create a link to the agency's profile page const link = ( - {item.agency_name} + {item.agency_name} ); // Round to 2 decimal places and don't show 0.00 - let percent = Math.round(parseFloat(item.percentage_of_total_budget_authority)*100)/100; + let percent = Math.round(parseFloat(item.percentage_of_total_budget_authority) * 100) / 100; - if (percent == 0.00) { + if (percent === 0.00) { percent = 'Less than 0.01%'; } else { From 1da975407e5359d5e297169dc688c2e426361a93 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Thu, 13 Jul 2017 16:53:51 -0400 Subject: [PATCH 14/97] Removing console.logs, removing react-addons-test-utils, updating react-dom and react-test-renderer --- package.json | 5 ++--- src/js/components/sharedComponents/DatePicker.jsx | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b1e6b1dfac..0c21d1dd67 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,8 @@ "jest": "^18.1.0", "json-loader": "^0.5.4", "node-sass": "^4.5.3", - "react-dom": "15.4.2", - "react-test-renderer": "15.4.2", + "react-dom": "^15.6.0", + "react-test-renderer": "^15.6.0", "sass-loader": "^6.0.6", "sinon": "^2.3.5", "style-loader": "^0.18.2", @@ -89,7 +89,6 @@ "r-dom": "^2.3.2", "react": "15.6.1", "react-addons-perf": "15.4.2", - "react-addons-test-utils": "15.6.0", "react-addons-update": "15.6.0", "react-aria-modal": "^2.6.0", "react-custom-scrollbars": "^4.1.2", diff --git a/src/js/components/sharedComponents/DatePicker.jsx b/src/js/components/sharedComponents/DatePicker.jsx index 393b7807ac..d3883d17a7 100644 --- a/src/js/components/sharedComponents/DatePicker.jsx +++ b/src/js/components/sharedComponents/DatePicker.jsx @@ -110,7 +110,6 @@ export default class DatePicker extends React.Component { } handleDatePick(day) { - console.log(day); this.props.onDateChange(day, this.props.type); this.props.hideError(); // close the popup if is shown @@ -122,7 +121,6 @@ export default class DatePicker extends React.Component { } handleTypedDate(e) { - console.log(e.target.value); // update the string state of the input field this.setState({ inputValue: e.target.value From 4a94cb4a593ac49b13581c3477cdc0b69b71fdff Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Fri, 14 Jul 2017 09:42:24 -0400 Subject: [PATCH 15/97] Jest update - breaks several tests. Added missing props to remove test warnings. --- package.json | 4 +-- .../RecipientLocationContainer-test.jsx | 25 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 0c21d1dd67..5cfd90f9ad 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "extract-text-webpack-plugin": "^2.1.2", "file-loader": "^0.11.2", "html-webpack-plugin": "^2.28.0", - "jest": "^18.1.0", + "jest": "^20.0.4", "json-loader": "^0.5.4", "node-sass": "^4.5.3", "react-dom": "^15.6.0", @@ -74,7 +74,7 @@ "fixed-data-table": "0.6.3", "history": "^4.6.1", "immutable": "^3.8.1", - "jest-cli": "^18.1.0", + "jest-cli": "^20.0.4", "js-cookie": "^2.1.0", "keyboardjs": "^2.3.3", "lodash": "^4.6.1", diff --git a/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx b/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx index 4a51c8d81d..4bd27d77f1 100644 --- a/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx +++ b/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx @@ -76,7 +76,8 @@ describe('RecipientLocationContainer', () => { setAutocompleteRecipientLocations: recipientActions.setAutocompleteRecipientLocations, selectedRecipientLocations: new OrderedMap(), - autocompleteRecipientLocations: [] + autocompleteRecipientLocations: [], + toggleRecipientLocation: jest.fn() }); const searchQuery = { @@ -112,7 +113,8 @@ describe('RecipientLocationContainer', () => { setAutocompleteRecipientLocations: recipientActions.setAutocompleteRecipientLocations, selectedRecipientLocations: new OrderedMap(), - autocompleteRecipientLocations: [] + autocompleteRecipientLocations: [], + toggleRecipientLocation: jest.fn() }); const searchQuery = { target: { @@ -152,7 +154,8 @@ describe('RecipientLocationContainer', () => { reduxFilters: initialFilters, setAutocompleteRecipientLocations: mockReduxAction, selectedRecipientLocations: new OrderedMap(), - autocompleteRecipientLocations: [] + autocompleteRecipientLocations: [], + toggleRecipientLocation: jest.fn() }); const queryAutocompleteRecipientLocationsSpy = sinon @@ -191,7 +194,8 @@ describe('RecipientLocationContainer', () => { reduxFilters: initialFilters, setAutocompleteRecipientLocations: mockReduxAction, selectedRecipientLocations: new OrderedMap(), - autocompleteRecipientLocations: [] + autocompleteRecipientLocations: [], + toggleRecipientLocation: jest.fn() }); // set up spies @@ -235,24 +239,20 @@ describe('RecipientLocationContainer', () => { }]; // setup mock redux actions for handling search results - const mockReduxAction = jest.fn((args) => { - expect(args).toEqual(reduxState); - }); + const mockReduxAction = jest.fn(); // Set up the Container and call the function to type a single letter const recipientLocationContainer = setup({ reduxFilters: initialFilters, setAutocompleteRecipientLocations: mockReduxAction, autocompleteRecipientLocations: reduxState, - selectedRecipientLocations: new OrderedMap() + selectedRecipientLocations: new OrderedMap(), + toggleRecipientLocation: jest.fn() }); // Mock the search helper to resolve with the mocked response mockSearchHelper('fetchLocations', 'resolve', apiResponse); - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(10000); - // Run all ticks jest.runAllTicks(); @@ -272,7 +272,8 @@ describe('RecipientLocationContainer', () => { expect(queryAutocompleteRecipientLocationsSpy.callCount).toEqual(1); expect(parseAutocompleteRecipientLocationsSpy .calledWith(queryAutocompleteRecipientLocationsSpy)); - expect(mockReduxAction).toHaveBeenCalled(); + + expect(mockReduxAction).toBeCalled(); // Reset the mock unmockSearchHelper(); From b681f077e7029fc8d3f8af114dc51343194be256 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Fri, 14 Jul 2017 11:02:55 -0400 Subject: [PATCH 16/97] Agencies table styling --- .../agencyLanding/agencyLandingPage.scss | 5 +++ .../table/cells/_agencyLandingCell.scss | 4 +- .../table/cells/_agencyLandingHeaderCell.scss | 6 +-- .../pages/agencyLanding/table/table.scss | 38 ++++++++++++++++--- .../AgencyLandingResultsSection.jsx | 3 +- .../table/AgencyLandingTable.jsx | 10 +++-- .../table/cells/AgencyLinkCell.jsx | 2 +- .../agencyLanding/AgencyLandingContainer.jsx | 3 +- .../AgencyLandingHeaderCellContainer.jsx | 7 ++-- .../agencyLanding/agenciesTableFields.js | 6 +++ 10 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/_scss/pages/agencyLanding/agencyLandingPage.scss b/src/_scss/pages/agencyLanding/agencyLandingPage.scss index a208d4c6fe..b8138235f1 100644 --- a/src/_scss/pages/agencyLanding/agencyLandingPage.scss +++ b/src/_scss/pages/agencyLanding/agencyLandingPage.scss @@ -14,6 +14,10 @@ h3 { margin-top: 0; } + p { + color: $color-gray-medium; + margin-bottom: rem(30); + } } .agency-landing-container { .agency-landing-section { @@ -21,6 +25,7 @@ &.results-count { font-style: italic; padding: rem(20) 0; + font-size: rem(16); } } @include agencyLandingSearch; diff --git a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss index c91886cdca..cfac113062 100644 --- a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss +++ b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss @@ -1,11 +1,13 @@ @mixin agencyLandingCell() { .cell-content { padding: rem(12) rem(16); - font-size: rem(12); color: $color-base; box-sizing: border-box; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + font-size: rem(16); + line-height: 23px; + float: right; } } \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss index d7481752d8..4aa83dffae 100644 --- a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss +++ b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss @@ -1,13 +1,13 @@ @mixin agencyLandingHeader() { .cell-content { - //background-color: $color-gray; white-space: normal; + font-size: rem(18); font-weight: 600; - font-size: rem(14); - line-height: rem(28); + line-height: 25px; color: $color-base; cursor: pointer; + float: right; .header-sort { display: table; diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss index c311b6b036..b89ec9e3a4 100644 --- a/src/_scss/pages/agencyLanding/table/table.scss +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -3,15 +3,17 @@ @import '../../../lib/ibTable/ibTable'; margin-top: rem(15); display: block; - border: 1px solid $color-gray-light; - // placeholder background for when the user scrolls really fast - background: repeating-linear-gradient( $color-white, $color-white 40px, $color-gray-lightest 40px, $color-gray-lightest 80px); &.no-results { border: none; } .award-result-generic-cell { @import "./cells/_agencyLandingCell"; @include agencyLandingCell(); + &.agency-link-cell { + .cell-content { + float: left; + } + } } .award-result-header-cell { @import "./cells/_agencyLandingHeaderCell"; @@ -21,8 +23,32 @@ .row-even { background-color: #f7f7f7; } - // override the header style for a bottom border - .ibt-header { - //border-bottom: 1px solid #ADAFB4; + + .ibt-table-container { + // override the header style + .ibt-header { + border-bottom: 1px solid #ADAFB4; + .ibt-header-cell { + background-color: $color-white; + &:first-child { + .award-result-header-cell { + .cell-content { + float: left; + } + } + } + } + } + // placeholder background for when the user scrolls really fast, with wider strips to match larger row height + .ibt-table-body-container { + .ibt-table-body { + background: repeating-linear-gradient( + $color-white, + $color-white 50px, + #f7f7f7 50px, + #f7f7f7 100px + ); + } + } } } \ No newline at end of file diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx index 0b7c8e36fe..172e5a2020 100644 --- a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -38,8 +38,7 @@ export default class AgencyLandingResultsSection extends React.Component { } setTableWidth() { - // subtract 2px from the width to account for the table borders (2 * 1px on each side) - const tableWidth = this.tableWidthController.clientWidth - 2; + const tableWidth = this.tableWidthController.clientWidth; this.setState({ tableWidth }); } diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 396cf443e5..ef2edf8600 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -19,7 +19,7 @@ const propTypes = { visibleWidth: React.PropTypes.number }; -const rowHeight = 40; +const rowHeight = 50; // setting the table height to a partial row prevents double bottom borders and also clearly // indicates when there's more data const tableHeight = 12.5 * rowHeight; @@ -78,7 +78,9 @@ export default class AgencyLandingTable extends React.PureComponent { const HeaderCell = this.props.headerCellClass; const columns = this.props.columns.map((column, i) => { - totalWidth += column.width; + // For this table, make each column's width a percentage of the visible width + const adjustedWidth = (this.props.visibleWidth * column.width ); + totalWidth += adjustedWidth; const isLast = i === this.props.columns.length - 1; let cellName = null; if (column.columnName === 'agency_profile_link') { @@ -104,7 +106,7 @@ export default class AgencyLandingTable extends React.PureComponent { ); } return { - width: column.width, + width: adjustedWidth, name: column.columnName, columnId: `${column.columnName}`, rowClassName: this.rowClassName, @@ -142,7 +144,7 @@ export default class AgencyLandingTable extends React.PureComponent { rowHeight={rowHeight} rowCount={this.props.results.length} headerHeight={50} - width={calculatedValues.width} + width={this.props.visibleWidth} maxWidth={this.props.visibleWidth} maxHeight={tableHeight} columns={calculatedValues.columns} diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx index 775e2af62b..bb08d6ca35 100644 --- a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -33,7 +33,7 @@ export default class AgencyLinkCell extends React.Component { } return ( -
+
{content}
diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 09743a71d4..556d192f9c 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -67,12 +67,13 @@ export class AgencyLandingContainer extends React.Component { showColumns() { const columns = []; const sortOrder = AgenciesTableFields.defaultSortDirection; + const widths = AgenciesTableFields.columnWidthPercentage; AgenciesTableFields.order.forEach((col) => { const column = { columnName: col, displayName: AgenciesTableFields[col], - width: measureTableHeader(AgenciesTableFields[col]), + width: widths[col], defaultDirection: sortOrder[col] }; columns.push(column); diff --git a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx index ba316b1ebd..86da4fd079 100644 --- a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx +++ b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx @@ -7,15 +7,14 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -// just import the two relevant actions -import { setAgenciesOrder, resetAgenciesOrder } from 'redux/actions/agencyLanding/agencyLandingActions'; +// just import the relevant action(s) +import { setAgenciesOrder } from 'redux/actions/agencyLanding/agencyLandingActions'; import ResultsTableHeaderCell from 'components/search/table/cells/ResultsTableHeaderCell'; // combine the action functions into an object for the react-redux bindings const actions = { - setAgenciesOrder, - resetAgenciesOrder + setAgenciesOrder }; const propTypes = { diff --git a/src/js/dataMapping/agencyLanding/agenciesTableFields.js b/src/js/dataMapping/agencyLanding/agenciesTableFields.js index 5e891704f3..b592d8a586 100644 --- a/src/js/dataMapping/agencyLanding/agenciesTableFields.js +++ b/src/js/dataMapping/agencyLanding/agenciesTableFields.js @@ -4,6 +4,12 @@ const agenciesTableFields = { budget_authority_amount: 'desc', percentage_of_total_budget_authority: 'desc' }, + // Fraction of the visible width the column should take up + columnWidthPercentage: { + agency_profile_link: 0.35, + budget_authority_amount: 0.3, + percentage_of_total_budget_authority: 0.35 + }, defaultSortField: 'agency_name', order: [ 'agency_profile_link', From efc832fbacae5bfa1f97d4ce5a110c52e030deab Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Fri, 14 Jul 2017 12:56:40 -0400 Subject: [PATCH 17/97] Adding new PSC and NAICS filter UIs --- src/_scss/pages/search/_filters.scss | 1 + .../filters/otherFilters/otherFilters.scss | 22 +++ src/js/components/search/SearchSidebar.jsx | 4 +- .../search/filters/cfda/CFDASearch.jsx | 16 +- .../search/filters/cfda/SelectedCFDA.jsx | 4 +- .../search/filters/cfda/ShownCFDA.jsx | 2 +- .../search/filters/naics/NAICSSearch.jsx | 38 ++++ .../search/filters/naics/SelectedNAICS.jsx | 37 ++++ .../search/filters/naics/ShownNAICS.jsx | 29 +++ .../filters/otherFilters/OtherFilters.jsx | 23 +++ .../search/filters/psc/PSCSearch.jsx | 38 ++++ .../search/filters/psc/SelectedPSC.jsx | 37 ++++ .../search/filters/psc/ShownPSC.jsx | 29 +++ .../search/filters/cfda/CFDAListContainer.jsx | 12 +- .../filters/naics/NAICSListContainer.jsx | 176 ++++++++++++++++++ .../filters/naics/NAICSSearchContainer.jsx | 72 +++++++ .../search/filters/psc/PSCListContainer.jsx | 176 ++++++++++++++++++ .../search/filters/psc/PSCSearchContainer.jsx | 72 +++++++ src/js/helpers/cfdaFormatter.js | 26 --- src/js/helpers/otherFiltersFormatter.js | 57 ++++++ src/js/helpers/searchHelper.js | 51 +++++ src/js/models/search/SearchOperation.js | 20 +- .../models/search/queryBuilders/CFDAQuery.js | 26 --- .../search/queryBuilders/OtherFiltersQuery.js | 62 ++++++ .../actions/search/autocompleteActions.js | 17 +- .../actions/search/searchFilterActions.js | 14 ++ .../reducers/search/autocompleteReducer.js | 9 + .../search/filters/CFDAFilterFunctions.js | 0 .../search/filters/OtherFilterFunctions.js | 62 ++++++ .../reducers/search/searchFiltersReducer.js | 28 ++- 30 files changed, 1079 insertions(+), 81 deletions(-) create mode 100644 src/_scss/pages/search/filters/otherFilters/otherFilters.scss create mode 100644 src/js/components/search/filters/naics/NAICSSearch.jsx create mode 100644 src/js/components/search/filters/naics/SelectedNAICS.jsx create mode 100644 src/js/components/search/filters/naics/ShownNAICS.jsx create mode 100644 src/js/components/search/filters/otherFilters/OtherFilters.jsx create mode 100644 src/js/components/search/filters/psc/PSCSearch.jsx create mode 100644 src/js/components/search/filters/psc/SelectedPSC.jsx create mode 100644 src/js/components/search/filters/psc/ShownPSC.jsx create mode 100644 src/js/containers/search/filters/naics/NAICSListContainer.jsx create mode 100644 src/js/containers/search/filters/naics/NAICSSearchContainer.jsx create mode 100644 src/js/containers/search/filters/psc/PSCListContainer.jsx create mode 100644 src/js/containers/search/filters/psc/PSCSearchContainer.jsx delete mode 100644 src/js/helpers/cfdaFormatter.js create mode 100644 src/js/helpers/otherFiltersFormatter.js delete mode 100644 src/js/models/search/queryBuilders/CFDAQuery.js create mode 100644 src/js/models/search/queryBuilders/OtherFiltersQuery.js delete mode 100644 src/js/redux/reducers/search/filters/CFDAFilterFunctions.js create mode 100644 src/js/redux/reducers/search/filters/OtherFilterFunctions.js diff --git a/src/_scss/pages/search/_filters.scss b/src/_scss/pages/search/_filters.scss index fcc57ad328..8f524df461 100644 --- a/src/_scss/pages/search/_filters.scss +++ b/src/_scss/pages/search/_filters.scss @@ -8,6 +8,7 @@ @import "./filters/recipient/recipient"; @import "./filters/awardID/awardID"; @import "./filters/awardAmount/awardAmount"; + @import "./filters/otherFilters/otherFilters"; @import "../../components/_comingSoon"; @import "../../components/_checkboxes"; diff --git a/src/_scss/pages/search/filters/otherFilters/otherFilters.scss b/src/_scss/pages/search/filters/otherFilters/otherFilters.scss new file mode 100644 index 0000000000..b8632a5753 --- /dev/null +++ b/src/_scss/pages/search/filters/otherFilters/otherFilters.scss @@ -0,0 +1,22 @@ +.cfda-filter, .psc-filter, .naics-filter { + @import "elements/filters/_errorMessage"; + @import "elements/filters/_typeahead"; + @import "elements/filters/_selectedFilterBtn"; + @import "mixins/selectedFilterWrap"; + + .filter-item-wrap { + p { + margin-top: rem(5); + margin-bottom: rem(5); + } + } + .shown { + min-height: rem(18); + } + .visually-hidden { + display: none; + } + .selected-filters { + @include selected-filter-wrap; + } +} \ No newline at end of file diff --git a/src/js/components/search/SearchSidebar.jsx b/src/js/components/search/SearchSidebar.jsx index 9ca80ea0ac..04a7da0873 100644 --- a/src/js/components/search/SearchSidebar.jsx +++ b/src/js/components/search/SearchSidebar.jsx @@ -16,7 +16,7 @@ import KeywordContainer from 'containers/search/filters/KeywordContainer'; import AwardIDSearchContainer from 'containers/search/filters/awardID/AwardIDSearchContainer'; import AwardAmountSearchContainer from 'containers/search/filters/awardAmount/AwardAmountSearchContainer'; -import CFDASearchContainer from 'containers/search/filters/cfda/CFDASearchContainer'; +import OtherFilters from 'components/search/filters/otherFilters/OtherFilters'; import { Filter as FilterIcon } from 'components/sharedComponents/icons/Icons'; import FilterSidebar from 'components/sharedComponents/filterSidebar/FilterSidebar'; @@ -45,7 +45,7 @@ const filters = { AwardTypeContainer, AwardIDSearchContainer, AwardAmountSearchContainer, - CFDASearchContainer + OtherFilters ] }; diff --git a/src/js/components/search/filters/cfda/CFDASearch.jsx b/src/js/components/search/filters/cfda/CFDASearch.jsx index e1a78cbfe4..31da6e5e77 100644 --- a/src/js/components/search/filters/cfda/CFDASearch.jsx +++ b/src/js/components/search/filters/cfda/CFDASearch.jsx @@ -16,19 +16,19 @@ const propTypes = { export default class CFDASearch extends React.Component { render() { - let selectedLocations = null; + let selectedCFDA = null; if (this.props.selectedCFDA.size > 0) { - selectedLocations = (); + selectedCFDA = (); } return ( -
+
-

CFDA

- - {selectedLocations} +

CFDA

+ + {selectedCFDA}
); diff --git a/src/js/components/search/filters/cfda/SelectedCFDA.jsx b/src/js/components/search/filters/cfda/SelectedCFDA.jsx index 7b3a173ff3..74a6558f38 100644 --- a/src/js/components/search/filters/cfda/SelectedCFDA.jsx +++ b/src/js/components/search/filters/cfda/SelectedCFDA.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import * as CFDAFormatter from 'helpers/cfdaFormatter'; +import * as OtherFiltersFormatter from 'helpers/otherFiltersFormatter'; import ShownCFDA from './ShownCFDA'; const propTypes = { @@ -21,7 +21,7 @@ export default class SelectedCFDA extends React.Component { const cfda = entry[1]; const value = (); shownCFDA.push(value); diff --git a/src/js/components/search/filters/cfda/ShownCFDA.jsx b/src/js/components/search/filters/cfda/ShownCFDA.jsx index ee8be61906..b361259fe7 100644 --- a/src/js/components/search/filters/cfda/ShownCFDA.jsx +++ b/src/js/components/search/filters/cfda/ShownCFDA.jsx @@ -1,5 +1,5 @@ /** - * ShownLocation.jsx + * ShownCFDA.jsx * Created by Emily Gullo 07/10/2017 **/ diff --git a/src/js/components/search/filters/naics/NAICSSearch.jsx b/src/js/components/search/filters/naics/NAICSSearch.jsx new file mode 100644 index 0000000000..0921bfb4eb --- /dev/null +++ b/src/js/components/search/filters/naics/NAICSSearch.jsx @@ -0,0 +1,38 @@ +/** + * NAICSSearch.jsx + * Created by Emily Gullo 07/14/2017 + **/ + +import React from 'react'; + +import NAICSListContainer from 'containers/search/filters/naics/NAICSListContainer'; +import SelectedNAICS from './SelectedNAICS'; + +const propTypes = { + selectNAICS: React.PropTypes.func, + removeNAICS: React.PropTypes.func, + selectedNAICS: React.PropTypes.object +}; + +export default class NAICSSearch extends React.Component { + render() { + let selectedNAICS = null; + if (this.props.selectedNAICS.size > 0) { + selectedNAICS = (); + } + + return ( +
+
+

NAICS

+ + {selectedNAICS} +
+
+ ); + } +} + +NAICSSearch.propTypes = propTypes; diff --git a/src/js/components/search/filters/naics/SelectedNAICS.jsx b/src/js/components/search/filters/naics/SelectedNAICS.jsx new file mode 100644 index 0000000000..5d5a713b08 --- /dev/null +++ b/src/js/components/search/filters/naics/SelectedNAICS.jsx @@ -0,0 +1,37 @@ +/** + * SelectedNAICS.jsx + * Created by Emily Gullo 07/14/2017 + **/ + +import React from 'react'; + +import * as OtherFiltersFormatter from 'helpers/otherFiltersFormatter'; +import ShownNAICS from './ShownNAICS'; + +const propTypes = { + selectedNAICS: React.PropTypes.object, + removeNAICS: React.PropTypes.func +}; + +export default class SelectedNAICS extends React.Component { + render() { + const shownNAICS = []; + this.props.selectedNAICS.entrySeq().forEach((entry) => { + const key = entry[0]; + const naics = entry[1]; + const value = (); + shownNAICS.push(value); + }); + + return ( +
+ {shownNAICS} +
+ ); + } +} +SelectedNAICS.propTypes = propTypes; diff --git a/src/js/components/search/filters/naics/ShownNAICS.jsx b/src/js/components/search/filters/naics/ShownNAICS.jsx new file mode 100644 index 0000000000..c36ab2db37 --- /dev/null +++ b/src/js/components/search/filters/naics/ShownNAICS.jsx @@ -0,0 +1,29 @@ +/** + * ShownNAICS.jsx + * Created by Emily Gullo 07/14/2017 + **/ + +import React from 'react'; +import * as Icons from 'components/sharedComponents/icons/Icons'; + +const propTypes = { + removeNAICS: React.PropTypes.func, + label: React.PropTypes.string +}; + +export default class ShownNAICS extends React.Component { + + render() { + return ( + + ); + } +} +ShownNAICS.propTypes = propTypes; diff --git a/src/js/components/search/filters/otherFilters/OtherFilters.jsx b/src/js/components/search/filters/otherFilters/OtherFilters.jsx new file mode 100644 index 0000000000..87b359ae07 --- /dev/null +++ b/src/js/components/search/filters/otherFilters/OtherFilters.jsx @@ -0,0 +1,23 @@ +/** + * OtherFilters.jsx + * Created by Emily GUllo on 6/23/17. + */ + +import React from 'react'; +import CFDASearchContainer from 'containers/search/filters/cfda/CFDASearchContainer'; +import NAICSSearchContainer from 'containers/search/filters/naics/NAICSSearchContainer'; +import PSCSearchContainer from 'containers/search/filters/psc/PSCSearchContainer'; + +export default class OtherFilters extends React.Component { + + render() { + return ( +
+ + + +
+ ); + } +} + diff --git a/src/js/components/search/filters/psc/PSCSearch.jsx b/src/js/components/search/filters/psc/PSCSearch.jsx new file mode 100644 index 0000000000..a384b2e356 --- /dev/null +++ b/src/js/components/search/filters/psc/PSCSearch.jsx @@ -0,0 +1,38 @@ +/** + * PSCSearch.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; + +import PSCListContainer from 'containers/search/filters/psc/PSCListContainer'; +import SelectedPSC from './SelectedPSC'; + +const propTypes = { + selectPSC: React.PropTypes.func, + removePSC: React.PropTypes.func, + selectedPSC: React.PropTypes.object +}; + +export default class PSCSearch extends React.Component { + render() { + let selectedPSC = null; + if (this.props.selectedPSC.size > 0) { + selectedPSC = (); + } + + return ( +
+
+

PSC

+ + {selectedPSC} +
+
+ ); + } +} + +PSCSearch.propTypes = propTypes; diff --git a/src/js/components/search/filters/psc/SelectedPSC.jsx b/src/js/components/search/filters/psc/SelectedPSC.jsx new file mode 100644 index 0000000000..13fe335d4a --- /dev/null +++ b/src/js/components/search/filters/psc/SelectedPSC.jsx @@ -0,0 +1,37 @@ +/** + * SelectedPSC.jsx + * Created by Emily Gullo 07/14/2017 + **/ + +import React from 'react'; + +import * as OtherFiltersFormatter from 'helpers/otherFiltersFormatter'; +import ShownPSC from './ShownPSC'; + +const propTypes = { + selectedPSC: React.PropTypes.object, + removePSC: React.PropTypes.func +}; + +export default class SelectedPSC extends React.Component { + render() { + const shownPSC = []; + this.props.selectedPSC.entrySeq().forEach((entry) => { + const key = entry[0]; + const psc = entry[1]; + const value = (); + shownPSC.push(value); + }); + + return ( +
+ {shownPSC} +
+ ); + } +} +SelectedPSC.propTypes = propTypes; diff --git a/src/js/components/search/filters/psc/ShownPSC.jsx b/src/js/components/search/filters/psc/ShownPSC.jsx new file mode 100644 index 0000000000..674bef04e0 --- /dev/null +++ b/src/js/components/search/filters/psc/ShownPSC.jsx @@ -0,0 +1,29 @@ +/** + * ShownPSC.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; +import * as Icons from 'components/sharedComponents/icons/Icons'; + +const propTypes = { + removePSC: React.PropTypes.func, + label: React.PropTypes.string +}; + +export default class ShownPSC extends React.Component { + + render() { + return ( + + ); + } +} +ShownPSC.propTypes = propTypes; diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index 41fdea269d..65ac9201fc 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -82,7 +82,7 @@ class CFDAListContainer extends React.Component { if (this.cfdaSearchRequest) { // A request is currently in-flight, cancel it - this.locationSearchRequest.cancel(); + this.cfdaSearchRequest.cancel(); } const cfdaSearchParams = { @@ -97,11 +97,11 @@ class CFDAListContainer extends React.Component { const data = res.data; let autocompleteData = []; - // Remove 'identifier' from selected locations to enable comparison + // Remove 'identifier' from selected cfdas to enable comparison const selectedCFDA = this.props.selectedCFDA.toArray() .map((cfda) => omit(cfda, 'identifier')); - // Filter out any selectedLocations that may be in the result set + // Filter out any selected cfdas that may be in the result set if (selectedCFDA && selectedCFDA.length > 0) { autocompleteData = differenceWith(data, selectedCFDA, isEqual); } @@ -134,12 +134,12 @@ class CFDAListContainer extends React.Component { this.props.setAutocompleteCFDA([]); } - handleTextInput(locationInput) { - // Clear existing locations to ensure user can't select an old or existing one + handleTextInput(cfdaInput) { + // Clear existing cfdas to ensure user can't select an old or existing one this.props.setAutocompleteCFDA([]); // Grab input, clear any exiting timeout - const input = locationInput.target.value; + const input = cfdaInput.target.value; window.clearTimeout(this.timeout); // Perform search if user doesn't type again for 300ms diff --git a/src/js/containers/search/filters/naics/NAICSListContainer.jsx b/src/js/containers/search/filters/naics/NAICSListContainer.jsx new file mode 100644 index 0000000000..91d007150c --- /dev/null +++ b/src/js/containers/search/filters/naics/NAICSListContainer.jsx @@ -0,0 +1,176 @@ +/** +* NAICSListContainer.jsx +* Created by Emily Gullo 07/14/2017 +**/ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { isEqual, upperCase, omit, differenceWith } from 'lodash'; +import { isCancel } from 'axios'; + +import * as SearchHelper from 'helpers/searchHelper'; +import * as autocompleteActions from 'redux/actions/search/autocompleteActions'; + +import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; + +const propTypes = { + selectNAICS: React.PropTypes.func, + setAutocompleteNAICS: React.PropTypes.func, + selectedNAICS: React.PropTypes.object, + autocompleteNAICS: React.PropTypes.array +}; + +class NAICSListContainer extends React.Component { + constructor(props) { + super(props); + + this.state = { + naicsSearchString: '', + autocompleteNAICS: [], + noResults: false + }; + + this.handleTextInput = this.handleTextInput.bind(this); + this.clearAutocompleteSuggestions = this.clearAutocompleteSuggestions.bind(this); + this.timeout = null; + } + + componentDidMount() { + this.parseAutocompleteNAICS(this.props.autocompleteNAICS); + } + + componentWillReceiveProps(nextProps) { + if (!isEqual(nextProps.autocompleteNAICS, this.props.autocompleteNAICS)) { + this.parseAutocompleteNAICS(nextProps.autocompleteNAICS); + } + } + + parseAutocompleteNAICS(naics) { + const values = []; + if (naics.length > 0) { + naics.forEach((item) => { + let placeType = upperCase(item.place_type); + if (item.parent !== null && + (item.place_type !== null && item.place_type !== 'COUNTRY')) { + placeType += ` in ${item.parent}`; + } + + values.push({ + title: item.place, + subtitle: placeType, + data: item + }); + }); + } + + this.setState({ + autocompleteNAICS: values + }); + } + + queryAutocompleteNAICS(input) { + this.setState({ + noResults: false + }); + + // Only search if input is 2 or more characters + if (input.length >= 2) { + this.setState({ + naicsSearchString: input + }); + + if (this.naicsSearchRequest) { + // A request is currently in-flight, cancel it + this.naicsSearchRequest.cancel(); + } + + const naicsSearchParams = { + value: this.state.naicsSearchString, + usage: "naics" + }; + + this.naicsSearchRequest = SearchHelper.fetchNAICS(naicsSearchParams); + + this.naicsSearchRequest.promise + .then((res) => { + const data = res.data; + let autocompleteData = []; + + // Remove 'identifier' from selected NAICS to enable comparison + const selectedNAICS = this.props.selectedNAICS.toArray() + .map((naics) => omit(naics, 'identifier')); + + // Filter out any selected NAICS that may be in the result set + if (selectedNAICS && selectedNAICS.length > 0) { + autocompleteData = differenceWith(data, selectedNAICS, isEqual); + } + else { + autocompleteData = data; + } + + this.setState({ + noResults: autocompleteData.length === 0 + }); + + // Add search results to Redux + this.props.setAutocompleteNAICS(autocompleteData); + }) + .catch((err) => { + if (!isCancel(err)) { + this.setState({ + noResults: true + }); + } + }); + } + else if (this.naicsSearchRequest) { + // A request is currently in-flight, cancel it + this.naicsSearchRequest.cancel(); + } + } + + clearAutocompleteSuggestions() { + this.props.setAutocompleteNAICS([]); + } + + handleTextInput(naicsInput) { + // Clear existing NAICS to ensure user can't select an old or existing one + this.props.setAutocompleteNAICS([]); + + // Grab input, clear any exiting timeout + const input = naicsInput.target.value; + window.clearTimeout(this.timeout); + + // Perform search if user doesn't type again for 300ms + this.timeout = window.setTimeout(() => { + this.queryAutocompleteNAICS(input); + }, 300); + } + + render() { + return ( + { + this.naicsList = input; + }} + clearAutocompleteSuggestions={this.clearAutocompleteSuggestions} + noResults={this.state.noResults} /> + ); + } + +} + +export default connect( + (state) => ({ autocompleteNAICS: state.autocompleteNAICS }), + (dispatch) => bindActionCreators(autocompleteActions, dispatch) +)(NAICSListContainer); + +NAICSListContainer.propTypes = propTypes; diff --git a/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx b/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx new file mode 100644 index 0000000000..0a8d84d518 --- /dev/null +++ b/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx @@ -0,0 +1,72 @@ +/** + * NAICSSearchContainer.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; + +import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; + +import NAICSSearch from 'components/search/filters/naics/NAICSSearch'; + +const propTypes = { + updateSelectedNAICS: React.PropTypes.func +}; + +const ga = require('react-ga'); + +class NAICSSearchContainer extends React.Component { + + static logPlaceFilterEvent(place) { + ga.event({ + category: 'Search Page Filter Applied', + action: `Applied NAICS Filter`, + label: place.toLowerCase() + }); + } + + constructor(props) { + super(props); + + // Bind functions + this.selectNAICS = this.selectNAICS.bind(this); + this.removeNAICS = this.removeNAICS.bind(this); + } + + selectNAICS(naics, isValid) { + // If naics exists and is valid + if (naics !== null && isValid) { + const updateParams = {}; + updateParams.naics = naics; + this.props.updateSelectedNAICS(updateParams); + + // Analytics + NAICSSearchContainer.logPlaceFilterEvent(naics.place); + } + } + + removeNAICS(naics) { + const updateParams = {}; + updateParams.naics = naics; + this.props.updateSelectedNAICS(updateParams); + } + + render() { + return ( + + ); + } +} + +NAICSSearchContainer.propTypes = propTypes; + +export default connect( + (state) => ({ + selectedNAICS: state.filters.selectedNAICS }), + (dispatch) => bindActionCreators(searchFilterActions, dispatch) +)(NAICSSearchContainer); diff --git a/src/js/containers/search/filters/psc/PSCListContainer.jsx b/src/js/containers/search/filters/psc/PSCListContainer.jsx new file mode 100644 index 0000000000..e064f8a537 --- /dev/null +++ b/src/js/containers/search/filters/psc/PSCListContainer.jsx @@ -0,0 +1,176 @@ +/** +* PSCListContainer.jsx +* Created by Emily Gullo 07/14/2017 +**/ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { isEqual, upperCase, omit, differenceWith } from 'lodash'; +import { isCancel } from 'axios'; + +import * as SearchHelper from 'helpers/searchHelper'; +import * as autocompleteActions from 'redux/actions/search/autocompleteActions'; + +import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; + +const propTypes = { + selectPSC: React.PropTypes.func, + setAutocompletePSC: React.PropTypes.func, + selectedPSC: React.PropTypes.object, + autocompletePSC: React.PropTypes.array +}; + +class PSCListContainer extends React.Component { + constructor(props) { + super(props); + + this.state = { + pscSearchString: '', + autocompletePSC: [], + noResults: false + }; + + this.handleTextInput = this.handleTextInput.bind(this); + this.clearAutocompleteSuggestions = this.clearAutocompleteSuggestions.bind(this); + this.timeout = null; + } + + componentDidMount() { + this.parseAutocompletePSC(this.props.autocompletePSC); + } + + componentWillReceiveProps(nextProps) { + if (!isEqual(nextProps.autocompletePSC, this.props.autocompletePSC)) { + this.parseAutocompletePSC(nextProps.autocompletePSC); + } + } + + parseAutocompletePSC(psc) { + const values = []; + if (psc.length > 0) { + psc.forEach((item) => { + let placeType = upperCase(item.place_type); + if (item.parent !== null && + (item.place_type !== null && item.place_type !== 'COUNTRY')) { + placeType += ` in ${item.parent}`; + } + + values.push({ + title: item.place, + subtitle: placeType, + data: item + }); + }); + } + + this.setState({ + autocompletePSC: values + }); + } + + queryAutocompletePSC(input) { + this.setState({ + noResults: false + }); + + // Only search if input is 2 or more characters + if (input.length >= 2) { + this.setState({ + pscSearchString: input + }); + + if (this.pscSearchRequest) { + // A request is currently in-flight, cancel it + this.pscSearchRequest.cancel(); + } + + const pscSearchParams = { + value: this.state.pscSearchString, + usage: "psc" + }; + + this.pscSearchRequest = SearchHelper.fetchPSC(pscSearchParams); + + this.pscSearchRequest.promise + .then((res) => { + const data = res.data; + let autocompleteData = []; + + // Remove 'identifier' from selected PSC to enable comparison + const selectedPSC = this.props.selectedPSC.toArray() + .map((psc) => omit(psc, 'identifier')); + + // Filter out any selected PSC that may be in the result set + if (selectedPSC && selectedPSC.length > 0) { + autocompleteData = differenceWith(data, selectedPSC, isEqual); + } + else { + autocompleteData = data; + } + + this.setState({ + noResults: autocompleteData.length === 0 + }); + + // Add search results to Redux + this.props.setAutocompletePSC(autocompleteData); + }) + .catch((err) => { + if (!isCancel(err)) { + this.setState({ + noResults: true + }); + } + }); + } + else if (this.pscSearchRequest) { + // A request is currently in-flight, cancel it + this.pscSearchRequest.cancel(); + } + } + + clearAutocompleteSuggestions() { + this.props.setAutocompletePSC([]); + } + + handleTextInput(pscInput) { + // Clear existing PSC to ensure user can't select an old or existing one + this.props.setAutocompletePSC([]); + + // Grab input, clear any exiting timeout + const input = pscInput.target.value; + window.clearTimeout(this.timeout); + + // Perform search if user doesn't type again for 300ms + this.timeout = window.setTimeout(() => { + this.queryAutocompletePSC(input); + }, 300); + } + + render() { + return ( + { + this.pscList = input; + }} + clearAutocompleteSuggestions={this.clearAutocompleteSuggestions} + noResults={this.state.noResults} /> + ); + } + +} + +export default connect( + (state) => ({ autocompletePSC: state.autocompletePSC }), + (dispatch) => bindActionCreators(autocompleteActions, dispatch) +)(PSCListContainer); + +PSCListContainer.propTypes = propTypes; diff --git a/src/js/containers/search/filters/psc/PSCSearchContainer.jsx b/src/js/containers/search/filters/psc/PSCSearchContainer.jsx new file mode 100644 index 0000000000..ecc3e6b47d --- /dev/null +++ b/src/js/containers/search/filters/psc/PSCSearchContainer.jsx @@ -0,0 +1,72 @@ +/** + * PSCSearchContainer.jsx + * Created by Emily Gullo 07/10/2017 + **/ + +import React from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; + +import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; + +import PSCSearch from 'components/search/filters/psc/PSCSearch'; + +const propTypes = { + updateSelectedPSC: React.PropTypes.func +}; + +const ga = require('react-ga'); + +class PSCSearchContainer extends React.Component { + + static logPlaceFilterEvent(place) { + ga.event({ + category: 'Search Page Filter Applied', + action: `Applied PSC Filter`, + label: place.toLowerCase() + }); + } + + constructor(props) { + super(props); + + // Bind functions + this.selectPSC = this.selectPSC.bind(this); + this.removePSC = this.removePSC.bind(this); + } + + selectPSC(psc, isValid) { + // If psc exists and is valid + if (psc !== null && isValid) { + const updateParams = {}; + updateParams.psc = psc; + this.props.updateSelectedPSC(updateParams); + + // Analytics + PSCSearchContainer.logPlaceFilterEvent(psc.place); + } + } + + removePSC(psc) { + const updateParams = {}; + updateParams.psc = psc; + this.props.updateSelectedPSC(updateParams); + } + + render() { + return ( + + ); + } +} + +PSCSearchContainer.propTypes = propTypes; + +export default connect( + (state) => ({ + selectedPSC: state.filters.selectedPSC }), + (dispatch) => bindActionCreators(searchFilterActions, dispatch) +)(PSCSearchContainer); diff --git a/src/js/helpers/cfdaFormatter.js b/src/js/helpers/cfdaFormatter.js deleted file mode 100644 index 79cde79fa3..0000000000 --- a/src/js/helpers/cfdaFormatter.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * cfdaFormatter.js - * Created by Emily Gullo on 07/10/2017 - */ - -import { startCase, toLower } from 'lodash'; - -/* eslint-disable import/prefer-default-export */ -// We only have one export but want to maintain consistency with other helpers -export const formatCFDA = (cfda) => { - let displayValue = ''; - - if (cfda.place_type !== null) { - displayValue = `${startCase(toLower(cfda.place_type))} | `; - } - - displayValue += `${cfda.place}`; - - if (cfda.parent !== null && - (cfda.place_type !== null && cfda.place_type !== 'COUNTRY')) { - displayValue += `, ${cfda.parent}`; - } - - return displayValue; -}; -/* eslint-enable import/prefer-default-export */ diff --git a/src/js/helpers/otherFiltersFormatter.js b/src/js/helpers/otherFiltersFormatter.js new file mode 100644 index 0000000000..be108bab28 --- /dev/null +++ b/src/js/helpers/otherFiltersFormatter.js @@ -0,0 +1,57 @@ +/** + * otherFiltersFormatter.js + * Created by Emily Gullo on 07/10/2017 + */ + +import { startCase, toLower } from 'lodash'; + +export const formatCFDA = (cfda) => { + let displayValue = ''; + + if (cfda.place_type !== null) { + displayValue = `${startCase(toLower(cfda.place_type))} | `; + } + + displayValue += `${cfda.place}`; + + if (cfda.parent !== null && + (cfda.place_type !== null && cfda.place_type !== 'COUNTRY')) { + displayValue += `, ${cfda.parent}`; + } + + return displayValue; +}; + +export const formatNAICS = (naics) => { + let displayValue = ''; + + if (naics.place_type !== null) { + displayValue = `${startCase(toLower(naics.place_type))} | `; + } + + displayValue += `${naics.place}`; + + if (naics.parent !== null && + (naics.place_type !== null && naics.place_type !== 'COUNTRY')) { + displayValue += `, ${naics.parent}`; + } + + return displayValue; +}; + +export const formatPSC = (psc) => { + let displayValue = ''; + + if (psc.place_type !== null) { + displayValue = `${startCase(toLower(psc.place_type))} | `; + } + + displayValue += `${psc.place}`; + + if (psc.parent !== null && + (psc.place_type !== null && psc.place_type !== 'COUNTRY')) { + displayValue += `, ${psc.parent}`; + } + + return displayValue; +}; diff --git a/src/js/helpers/searchHelper.js b/src/js/helpers/searchHelper.js index 216beae2bb..2f0d5cba84 100644 --- a/src/js/helpers/searchHelper.js +++ b/src/js/helpers/searchHelper.js @@ -129,6 +129,57 @@ export const fetchAgencies = (req) => { }; }; +// CFDA search for autocomplete +export const fetchCFDA = (req) => { + const source = CancelToken.source(); + return { + promise: Axios.request({ + url: 'v2/autocomplete/CFDA/', + baseURL: kGlobalConstants.API, + method: 'post', + data: req, + cancelToken: source.token + }), + cancel() { + source.cancel(); + } + }; +}; + +// NAICS search for autocomplete +export const fetchNAICS = (req) => { + const source = CancelToken.source(); + return { + promise: Axios.request({ + url: 'v2/autocomplete/NAICS/', + baseURL: kGlobalConstants.API, + method: 'post', + data: req, + cancelToken: source.token + }), + cancel() { + source.cancel(); + } + }; +}; + +// PSC search for autocomplete +export const fetchPSC = (req) => { + const source = CancelToken.source(); + return { + promise: Axios.request({ + url: 'v2/autocomplete/PSC/', + baseURL: kGlobalConstants.API, + method: 'post', + data: req, + cancelToken: source.token + }), + cancel() { + source.cancel(); + } + }; +}; + // Fetch Individual Award export const fetchAward = (num) => { const source = CancelToken.source(); diff --git a/src/js/models/search/SearchOperation.js b/src/js/models/search/SearchOperation.js index f3be79367b..68c222ef44 100644 --- a/src/js/models/search/SearchOperation.js +++ b/src/js/models/search/SearchOperation.js @@ -13,7 +13,7 @@ import * as RecipientQuery from './queryBuilders/RecipientQuery'; import * as KeywordQuery from './queryBuilders/KeywordQuery'; import * as AwardIDQuery from './queryBuilders/AwardIDQuery'; import * as AwardAmountQuery from './queryBuilders/AwardAmountQuery'; -import * as CFDAQuery from './queryBuilders/CFDAQuery'; +import * as OtherFiltersQuery from './queryBuilders/OtherFiltersQuery'; class SearchOperation { constructor() { @@ -47,6 +47,8 @@ class SearchOperation { this.awardAmounts = []; this.selectedCFDA = []; + this.selectedNAICS = []; + this.selectedPSC = []; this.searchContext = 'award'; } @@ -82,6 +84,8 @@ class SearchOperation { this.awardAmounts = state.awardAmounts.toArray(); this.selectedCFDA = state.selectedCFDA.toArray(); + this.selectedNAICS = state.selectedNAICS.toArray(); + this.selectesPSC = state.selectedPSC.toArray(); } commonParams() { @@ -159,10 +163,22 @@ class SearchOperation { // Add cfda query if (this.selectedCFDA.length > 0) { - filters.push(CFDAQuery.buildCFDAQuery( + filters.push(OtherFiltersQuery.buildCFDAQuery( this.selectedCFDA, this.searchContext)); } + // Add naics query + if (this.selectedNAICS.length > 0) { + filters.push(OtherFiltersQuery.buildNAICSQuery( + this.selectedNAICS, this.searchContext)); + } + + // Add psc query + if (this.selectedPSC.length > 0) { + filters.push(OtherFiltersQuery.buildPSCQuery( + this.selectedPSC, this.searchContext)); + } + return filters; } diff --git a/src/js/models/search/queryBuilders/CFDAQuery.js b/src/js/models/search/queryBuilders/CFDAQuery.js deleted file mode 100644 index c199f926e0..0000000000 --- a/src/js/models/search/queryBuilders/CFDAQuery.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Created by Emily Gullo 07/12/2017 - */ - -import * as FilterFields from 'dataMapping/search/filterFields'; -/* eslint-disable import/prefer-default-export */ -// We only have one export but want to maintain consistency with other queries -export const buildCFDAQuery = (cfdas, searchContext = 'award') => { - const field = FilterFields[`${searchContext}Fields`].cfda; - - const cfdaSet = []; - - // Push IDs of selected Awards - cfdas.forEach((cfda) => { - cfdaSet.push(cfda.id); - }); - - const filter = { - field, - operation: "in", - value: cfdaSet - }; - - return filter; -}; -/* eslint-enable import/prefer-default-export */ diff --git a/src/js/models/search/queryBuilders/OtherFiltersQuery.js b/src/js/models/search/queryBuilders/OtherFiltersQuery.js new file mode 100644 index 0000000000..5fd9e78825 --- /dev/null +++ b/src/js/models/search/queryBuilders/OtherFiltersQuery.js @@ -0,0 +1,62 @@ +/** + * Created by Emily Gullo 07/12/2017 + */ + +import * as FilterFields from 'dataMapping/search/filterFields'; + +export const buildCFDAQuery = (cfdaGroup, searchContext = 'award') => { + const field = FilterFields[`${searchContext}Fields`].cfda; + + const cfdaSet = []; + + // Push IDs of selected Awards + cfdaGroup.forEach((cfda) => { + cfdaSet.push(cfda.id); + }); + + const filter = { + field, + operation: "in", + value: cfdaSet + }; + + return filter; +}; + +export const buildNAICSQuery = (naicsGroup, searchContext = 'award') => { + const field = FilterFields[`${searchContext}Fields`].naics; + + const naicsSet = []; + + // Push IDs of selected Awards + naicsGroup.forEach((naics) => { + naicsSet.push(naics.id); + }); + + const filter = { + field, + operation: "in", + value: naicsSet + }; + + return filter; +}; + +export const buildPSCQuery = (pscGroup, searchContext = 'award') => { + const field = FilterFields[`${searchContext}Fields`].psc; + + const pscSet = []; + + // Push IDs of selected Awards + pscGroup.forEach((psc) => { + pscSet.push(psc.id); + }); + + const filter = { + field, + operation: "in", + value: pscSet + }; + + return filter; +}; diff --git a/src/js/redux/actions/search/autocompleteActions.js b/src/js/redux/actions/search/autocompleteActions.js index 448446f510..9562d0180a 100644 --- a/src/js/redux/actions/search/autocompleteActions.js +++ b/src/js/redux/actions/search/autocompleteActions.js @@ -2,12 +2,21 @@ * Created by michaelbray on 12/20/16. */ -/* eslint-disable import/prefer-default-export */ -// We only have one export but want to maintain consistency with other query modules - export const setAutocompleteLocations = (state) => ({ type: 'SET_AUTOCOMPLETE_LOCATIONS', locations: state }); -/* eslint-enable import/prefer-default-export */ +export const setAutocompleteCFDA = (state) => ({ + type: 'SET_AUTOCOMPLETE_CFDA', + cfda: state +}); + +export const setAutocompleteNAICS = (state) => ({ + type: 'SET_AUTOCOMPLETE_NAICS', + naics: state +}); +export const setAutocompletePSC = (state) => ({ + type: 'SET_AUTOCOMPLETE_PSC', + psc: state +}); diff --git a/src/js/redux/actions/search/searchFilterActions.js b/src/js/redux/actions/search/searchFilterActions.js index 3f4fa5cf40..30cdea525d 100644 --- a/src/js/redux/actions/search/searchFilterActions.js +++ b/src/js/redux/actions/search/searchFilterActions.js @@ -144,6 +144,20 @@ export const updateSelectedCFDA = (state) => ({ cfda: state.cfda }); +// NAICS Filter + +export const updateSelectedNAICS = (state) => ({ + type: 'UPDATE_SELECTED_NAICS', + cfda: state.naics +}); + +// PSC Filter + +export const updateSelectedPSC = (state) => ({ + type: 'UPDATE_SELECTED_PSC', + cfda: state.psc +}); + // Generic export const setSearchOrder = (state) => ({ diff --git a/src/js/redux/reducers/search/autocompleteReducer.js b/src/js/redux/reducers/search/autocompleteReducer.js index 2048a64fb5..f95df28a17 100644 --- a/src/js/redux/reducers/search/autocompleteReducer.js +++ b/src/js/redux/reducers/search/autocompleteReducer.js @@ -11,6 +11,15 @@ const autocompleteReducer = (state = initialState, action) => { case 'SET_AUTOCOMPLETE_LOCATIONS': { return concat([], action.locations); } + case 'SET_AUTOCOMPLETE_CFDA': { + return concat([], action.cfda); + } + case 'SET_AUTOCOMPLETE_NAICS': { + return concat([], action.naics); + } + case 'SET_AUTOCOMPLETE_PSC': { + return concat([], action.psc); + } default: return state; } diff --git a/src/js/redux/reducers/search/filters/CFDAFilterFunctions.js b/src/js/redux/reducers/search/filters/CFDAFilterFunctions.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/js/redux/reducers/search/filters/OtherFilterFunctions.js b/src/js/redux/reducers/search/filters/OtherFilterFunctions.js new file mode 100644 index 0000000000..6082de1e1e --- /dev/null +++ b/src/js/redux/reducers/search/filters/OtherFilterFunctions.js @@ -0,0 +1,62 @@ +/** + * Created by michaelbray on 12/12/16. + */ + +import { sortBy } from 'lodash'; + +export const udpatedSelectedCFDA = (state, value) => { + let updatedSet = state; + // generate an identifier string based on matched IDs and place name + const cfdaIdentifier = + `${sortBy(value.matched_ids).join(',')}_${value.place}_${value.place_type}`; + + if (updatedSet.has(cfdaIdentifier)) { + updatedSet = updatedSet.delete(cfdaIdentifier); + } + else { + const cfdaObject = Object.assign({}, value, { + identifier: cfdaIdentifier + }); + updatedSet = updatedSet.set(cfdaIdentifier, cfdaObject); + } + + return updatedSet; +}; + +export const udpatedSelectedNAICS = (state, value) => { + let updatedSet = state; + // generate an identifier string based on matched IDs and place name + const naicsIdentifier = + `${sortBy(value.matched_ids).join(',')}_${value.place}_${value.place_type}`; + + if (updatedSet.has(naicsIdentifier)) { + updatedSet = updatedSet.delete(naicsIdentifier); + } + else { + const naicsObject = Object.assign({}, value, { + identifier: naicsIdentifier + }); + updatedSet = updatedSet.set(naicsIdentifier, naicsObject); + } + + return updatedSet; +}; + +export const udpatedSelectedPSC = (state, value) => { + let updatedSet = state; + // generate an identifier string based on matched IDs and place name + const pscIdentifier = + `${sortBy(value.matched_ids).join(',')}_${value.place}_${value.place_type}`; + + if (updatedSet.has(pscIdentifier)) { + updatedSet = updatedSet.delete(pscIdentifier); + } + else { + const pscObject = Object.assign({}, value, { + identifier: pscIdentifier + }); + updatedSet = updatedSet.set(pscIdentifier, pscObject); + } + + return updatedSet; +}; diff --git a/src/js/redux/reducers/search/searchFiltersReducer.js b/src/js/redux/reducers/search/searchFiltersReducer.js index abd534e021..bd9427b242 100644 --- a/src/js/redux/reducers/search/searchFiltersReducer.js +++ b/src/js/redux/reducers/search/searchFiltersReducer.js @@ -12,7 +12,7 @@ import * as RecipientFilterFunctions from './filters/recipientFilterFunctions'; import * as AwardIDFilterFunctions from './filters/awardIDFilterFunctions'; import * as AwardAmountFilterFunctions from './filters/awardAmountFilterFunctions'; import * as BudgetCategoryFilterFunctions from './filters/budgetCategoryFilterFunctions'; -import * as CFDAFilterFunctions from './filters/CFDAFilterFunctions'; +import * as OtherFilterFunctions from './filters/OtherFilterFunctions'; // update this version when changes to the reducer structure are made // frontend will reject inbound hashed search filter sets with different versions because the @@ -33,7 +33,9 @@ export const requiredTypes = { awardType: Set, selectedAwardIDs: OrderedMap, awardAmounts: OrderedMap, - selectedCFDA: OrderedMap + selectedCFDA: OrderedMap, + selectedNAICS: OrderedMap, + selectedPSC: OrderedMap }; export const initialState = { @@ -56,7 +58,9 @@ export const initialState = { awardType: new Set(), selectedAwardIDs: new OrderedMap(), awardAmounts: new OrderedMap(), - selectedCFDA: new OrderedMap() + selectedCFDA: new OrderedMap(), + selectedNAICS: new OrderedMap(), + selectedPSC: new OrderedMap() }; const searchFiltersReducer = (state = initialState, action) => { @@ -203,11 +207,27 @@ const searchFiltersReducer = (state = initialState, action) => { // CFDA Filter case 'UPDATE_SELECTED_CFDA': { return Object.assign({}, state, { - selectedCFDA: CFDAFilterFunctions.updateSelectedCFDA( + selectedCFDA: OtherFilterFunctions.updateSelectedCFDA( state.selectedCFDA, action.cfda) }); } + // CFDA Filter + case 'UPDATE_SELECTED_NAICS': { + return Object.assign({}, state, { + selectedNAICS: OtherFilterFunctions.updateSelectedNAICS( + state.selectedNAICS, action.naics) + }); + } + + // CFDA Filter + case 'UPDATE_SELECTED_PSC': { + return Object.assign({}, state, { + selectedPSC: OtherFilterFunctions.updateSelectedPSC( + state.selectedPSC, action.psc) + }); + } + // Generic case 'UPDATE_SEARCH_FILTER_GENERIC': { return Object.assign({}, state, { From eadd32589b1721311676dc1419075d745673a634 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 14 Jul 2017 15:27:59 -0400 Subject: [PATCH 18/97] Async promise and improved searchHelper mock --- .babelrc | 7 +- package.json | 1 + .../RecipientLocationContainer-test.jsx | 80 ++----------------- .../recipientFilter/mocks/mockRecipient.js | 6 ++ .../recipientFilter/mocks/searchHelper.js | 15 ++++ 5 files changed, 35 insertions(+), 74 deletions(-) create mode 100644 tests/containers/search/filters/recipientFilter/mocks/mockRecipient.js create mode 100644 tests/containers/search/filters/recipientFilter/mocks/searchHelper.js diff --git a/.babelrc b/.babelrc index 3767309f41..cfa2386467 100644 --- a/.babelrc +++ b/.babelrc @@ -1,7 +1,12 @@ { "presets": [ "es2015", - "react" + "react", + ["env", { + "targets": { + "node": "current" + } + }] ], "plugins": [ ["module-resolver", { diff --git a/package.json b/package.json index 5cfd90f9ad..f3dd79b392 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "babel-jest": "^20.0.3", "babel-loader": "^7.1.0", "babel-plugin-module-resolver": "^2.7.1", + "babel-preset-env": "^1.6.0", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "clean-webpack-plugin": "^0.1.16", diff --git a/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx b/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx index 4bd27d77f1..6c4bd61d84 100644 --- a/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx +++ b/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx @@ -3,6 +3,11 @@ * Created by michaelbray on 2/17/17. */ +jest.mock('helpers/searchHelper', () => { + const helper = require('./mocks/searchHelper'); + return helper; +}); + import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; @@ -11,7 +16,6 @@ import { OrderedMap } from 'immutable'; import { RecipientLocationContainer } from 'containers/search/filters/recipient/RecipientLocationContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import * as recipientActions from 'redux/actions/search/recipientActions'; const setup = (props) => mount(); @@ -20,52 +24,6 @@ const initialFilters = { autocompleteRecipientLocations: [] }; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - -const apiResponse = [ - { - place_type: "COUNTY", - matched_ids: [22796], - place: "McLean", - parent: "KENTUCKY" - } -]; - -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; describe('RecipientLocationContainer', () => { describe('Handling text input', () => { @@ -95,9 +53,6 @@ describe('RecipientLocationContainer', () => { // Run fake timer for input delay jest.useFakeTimers().runTimersToTime(1000); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); - // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); @@ -133,9 +88,6 @@ describe('RecipientLocationContainer', () => { // Run fake timer for input delay jest.useFakeTimers().runTimersToTime(1000); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); - // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); expect(queryAutocompleteRecipientLocationsSpy.callCount).toEqual(1); @@ -226,7 +178,7 @@ describe('RecipientLocationContainer', () => { queryAutocompleteRecipientLocationsSpy.reset(); }); - it('should populate Recipients after performing the search', () => { + it('should populate Recipients after performing the search', async () => { // Setup redux state const reduxState = [{ '22796_McLean_COUNTY': { @@ -250,37 +202,19 @@ describe('RecipientLocationContainer', () => { toggleRecipientLocation: jest.fn() }); - // Mock the search helper to resolve with the mocked response - mockSearchHelper('fetchLocations', 'resolve', apiResponse); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteRecipientLocationsSpy = sinon.spy(recipientLocationContainer.instance(), 'queryAutocompleteRecipientLocations'); - const parseAutocompleteRecipientLocationsSpy = sinon - .spy(recipientLocationContainer.instance(), - 'parseAutocompleteRecipientLocations'); recipientLocationContainer.instance().queryAutocompleteRecipientLocations('Booz Allen'); - - // Run all ticks - jest.runAllTicks(); + await recipientLocationContainer.instance().recipientLocationSearchRequest.promise; expect(queryAutocompleteRecipientLocationsSpy.callCount).toEqual(1); - expect(parseAutocompleteRecipientLocationsSpy - .calledWith(queryAutocompleteRecipientLocationsSpy)); - expect(mockReduxAction).toBeCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteRecipientLocationsSpy.reset(); - parseAutocompleteRecipientLocationsSpy.reset(); }); }); }); diff --git a/tests/containers/search/filters/recipientFilter/mocks/mockRecipient.js b/tests/containers/search/filters/recipientFilter/mocks/mockRecipient.js new file mode 100644 index 0000000000..546840c6ff --- /dev/null +++ b/tests/containers/search/filters/recipientFilter/mocks/mockRecipient.js @@ -0,0 +1,6 @@ +export const mockLocationAutocomplete = [{ + place_type: "CITY", + matched_ids: [22516, 23056], + place: "MCLEAN", + parent: null +}]; diff --git a/tests/containers/search/filters/recipientFilter/mocks/searchHelper.js b/tests/containers/search/filters/recipientFilter/mocks/searchHelper.js new file mode 100644 index 0000000000..d9755903a7 --- /dev/null +++ b/tests/containers/search/filters/recipientFilter/mocks/searchHelper.js @@ -0,0 +1,15 @@ +import { mockLocationAutocomplete } from './mockRecipient'; + +// Location search for autocomplete +export const fetchLocations = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockLocationAutocomplete + }); + }); + }), + cancel: jest.fn() + } +); From 40ee5738d295862ed356421af2c4a65b9d029222 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Sun, 16 Jul 2017 20:21:14 -0400 Subject: [PATCH 19/97] Fixing some tests --- package.json | 2 +- tests/.eslintrc | 4 +- .../AccountProgramActivityContainer-test.jsx | 53 +++-- tests/containers/agency/agencyHelper.js | 44 ++++ .../ObligatedContainer-test.jsx | 86 +++---- .../containers/award/AwardContainer-test.jsx | 68 ++---- ...ontractTransactionsTableContainer-test.jsx | 12 +- .../RecipientLocationContainer-test.jsx | 7 +- .../recipientFilter/mocks/searchHelper.js | 15 -- .../containers/search/filters/searchHelper.js | 76 ++++++ .../GeoVisualizationSectionContainer-test.jsx | 141 ++--------- .../visualizations/mockVisualizations.js | 40 ++++ ...RankVisualizationSectionContainer-test.jsx | 220 ++---------------- .../account/mockAccountProgramActivities.js | 7 + .../redux/reducers/search/mock/mockFilters.js | 1 + .../reducers/search/mock}/mockRecipient.js | 0 16 files changed, 297 insertions(+), 479 deletions(-) create mode 100644 tests/containers/agency/agencyHelper.js delete mode 100644 tests/containers/search/filters/recipientFilter/mocks/searchHelper.js create mode 100644 tests/containers/search/filters/searchHelper.js create mode 100644 tests/containers/search/visualizations/mockVisualizations.js create mode 100644 tests/redux/reducers/account/mockAccountProgramActivities.js rename tests/{containers/search/filters/recipientFilter/mocks => redux/reducers/search/mock}/mockRecipient.js (100%) diff --git a/package.json b/package.json index f3dd79b392..7f50676e76 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "testRegex": "tests/.*-(test)\\.jsx?$", "verbose": true, "bail": false, - "collectCoverage": true, + "collectCoverage": false, "collectCoverageFrom": [ "src/js/containers/**/*.{js,jsx}", "src/js/redux/reducers/**/*.{js,jsx}", diff --git a/tests/.eslintrc b/tests/.eslintrc index b0f8fc578f..fa660a1c40 100644 --- a/tests/.eslintrc +++ b/tests/.eslintrc @@ -75,6 +75,8 @@ { "devDependencies": true } - ] + ], + // allow global require for tests + "global-require": [0] } } diff --git a/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx b/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx index d4b64338b3..fb7451e416 100644 --- a/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx +++ b/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx @@ -23,9 +23,12 @@ const account = { id: 2525 }; +jest.mock('helpers/searchHelper', () => require('../../search/filters/searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + describe('AccountProgramActivityContainer', () => { describe('updateFilter', () => { - it('should add a Program Activity that has been selected to Redux', () => { + it('should add a Program Activity that has been selected to Redux', async () => { const mockReduxAction = jest.fn((args) => { expect(args).toEqual('810'); }); @@ -35,8 +38,11 @@ describe('AccountProgramActivityContainer', () => { ); + await accountProgramActivityContainer.instance().searchRequest.promise; + const updateFilterSpy = sinon.spy(accountProgramActivityContainer.instance(), 'updateFilter'); @@ -51,7 +57,7 @@ describe('AccountProgramActivityContainer', () => { updateFilterSpy.reset(); }); - it('should remove a Program Activity that has been deselected from Redux', () => { + it('should remove a Program Activity that has been deselected from Redux', async () => { const mockReduxAction = jest.fn((args) => { expect(args).toEqual('810'); }); @@ -61,8 +67,11 @@ describe('AccountProgramActivityContainer', () => { ); + await accountProgramActivityContainer.instance().searchRequest.promise; + const updateFilterSpy = sinon.spy(accountProgramActivityContainer.instance(), 'updateFilter'); @@ -82,20 +91,21 @@ describe('AccountProgramActivityContainer', () => { }); describe('populateProgramActivities', () => { - it('should fetch program activities on load', () => { - jest.useFakeTimers(); - - const container = shallow(); + it('should fetch program activities on load', async () => { + const accountProgramActivityContainer = shallow( + ); // set up spy const populateProgramActivitiesSpy = sinon.spy( - container.instance(), 'populateProgramActivities'); + accountProgramActivityContainer.instance(), 'populateProgramActivities'); - container.instance().componentWillMount(); + accountProgramActivityContainer.instance().componentWillMount(); - // Run fake timer for input delay - jest.runAllTicks(); + await accountProgramActivityContainer.instance().searchRequest.promise; // everything should be updated now expect(populateProgramActivitiesSpy.callCount).toEqual(1); @@ -106,22 +116,23 @@ describe('AccountProgramActivityContainer', () => { }); describe('parseResultData', () => { - it('should parse retrieved program activities', () => { - jest.useFakeTimers(); - - const container = shallow(); + it('should parse retrieved program activities', async () => { + const accountProgramActivityContainer = shallow( + ); // set up spy const populateProgramActivitiesSpy = sinon.spy( - container.instance(), 'populateProgramActivities'); + accountProgramActivityContainer.instance(), 'populateProgramActivities'); const parseResultDataSpy = sinon.spy( - container.instance(), 'parseResultData'); + accountProgramActivityContainer.instance(), 'parseResultData'); - container.instance().populateProgramActivities(); + accountProgramActivityContainer.instance().populateProgramActivities(); - // Run fake timer for input delay - jest.runAllTicks(); + await accountProgramActivityContainer.instance().searchRequest.promise; // everything should be updated now expect(populateProgramActivitiesSpy.callCount).toEqual(1); diff --git a/tests/containers/agency/agencyHelper.js b/tests/containers/agency/agencyHelper.js new file mode 100644 index 0000000000..4a5232ba9b --- /dev/null +++ b/tests/containers/agency/agencyHelper.js @@ -0,0 +1,44 @@ +import { mockObligatedAmounts, mockCgacCode, mockFiscalQuarter } + from './visualizations/mocks/mockObligatedAmounts'; + +// Fetch Agency Obligated Amounts +export const fetchAgencyObligatedAmounts = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockObligatedAmounts + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Agency CGAC Code +export const fetchAgencyCgacCode = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockCgacCode + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Agency Fiscal Quarter +export const fetchAgencyFiscalQuarter = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockFiscalQuarter + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/agency/visualizations/ObligatedContainer-test.jsx b/tests/containers/agency/visualizations/ObligatedContainer-test.jsx index 6fa28ec151..9e363038e7 100644 --- a/tests/containers/agency/visualizations/ObligatedContainer-test.jsx +++ b/tests/containers/agency/visualizations/ObligatedContainer-test.jsx @@ -8,13 +8,6 @@ import { mount } from 'enzyme'; import sinon from 'sinon'; import { ObligatedContainer } from 'containers/agency/visualizations/ObligatedContainer'; -import * as AgencyHelper from 'helpers/agencyHelper'; - -import { mockObligatedAmounts, mockCgacCode, mockFiscalQuarter } from './mocks/mockObligatedAmounts'; - -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); // spy on specific functions inside the component const loadDataSpy = sinon.spy(ObligatedContainer.prototype, 'loadData'); @@ -28,6 +21,8 @@ const inboundProps = { activeFY: '2017' }; +jest.mock('helpers/agencyHelper', () => require('../../../containers/agency/agencyHelper')); + // mock the child component by replacing it with a function that returns a null element jest.mock('components/agency/visualizations/obligated/ObligatedVisualization', () => jest.fn(() => null)); @@ -40,63 +35,48 @@ jest.mock('containers/glossary/GlossaryButtonWrapperContainer', () => jest.mock('containers/glossary/GlossaryContainer', () => jest.fn(() => null)); -const mockAgencyHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - AgencyHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); +describe('ObligatedContainer', () => { + it('should make an API call for the selected agency obligated amounts on mount', async () => { + const container = mount(); - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; + await container.instance().searchRequest.promise; -const unmockAgencyHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/agencyHelper'); -}; + expect(loadDataSpy.callCount).toEqual(1); -describe('ObligatedContainer', () => { - it('should make an API call for the selected agency obligated amounts on mount', () => { - mockAgencyHelper('fetchAgencyObligatedAmounts', 'resolve', mockObligatedAmounts); - mockAgencyHelper('fetchAgencyCgacCode', 'resolve', mockCgacCode); - mockAgencyHelper('fetchAgencyFiscalQuarter', 'resolve', mockFiscalQuarter); + loadDataSpy.reset(); + setCgacCodeSpy.reset(); + setFiscalQuarterSpy.reset(); + }); - mount( { + const container = mount(); - jest.runAllTicks(); + await container.instance().searchRequest.promise; - expect(loadDataSpy.callCount).toEqual(1); expect(setCgacCodeSpy.callCount).toEqual(1); - expect(setFiscalQuarterSpy.callCount).toEqual(1); + loadDataSpy.reset(); + setCgacCodeSpy.reset(); + setFiscalQuarterSpy.reset(); + }); + + it('should make an API call for the selected agency fiscal quarters after loading CGAC data', async () => { + const container = mount(); - unmockAgencyHelper(); + await container.instance().searchRequest.promise; + + expect(setFiscalQuarterSpy.callCount).toEqual(1); + + loadDataSpy.reset(); + setCgacCodeSpy.reset(); + setFiscalQuarterSpy.reset(); }); it('should make a new API call for obligated amounts when the inbound agency ID prop' + ' changes', () => { - mockAgencyHelper('fetchAgencyObligatedAmounts', 'resolve', mockObligatedAmounts); - mockAgencyHelper('fetchAgencyCgacCode', 'resolve', mockCgacCode); - mockAgencyHelper('fetchAgencyFiscalQuarter', 'resolve', mockFiscalQuarter); - const container = mount(); @@ -108,11 +88,9 @@ describe('ObligatedContainer', () => { id: '555' }); - jest.runAllTicks(); - expect(loadDataMock).toHaveBeenCalledWith('555', inboundProps.activeFY); loadDataSpy.reset(); - - unmockAgencyHelper(); + setCgacCodeSpy.reset(); + setFiscalQuarterSpy.reset(); }); }); diff --git a/tests/containers/award/AwardContainer-test.jsx b/tests/containers/award/AwardContainer-test.jsx index d82cb824cc..246377cd83 100644 --- a/tests/containers/award/AwardContainer-test.jsx +++ b/tests/containers/award/AwardContainer-test.jsx @@ -8,15 +8,10 @@ import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; import { AwardContainer } from 'containers/award/AwardContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import AwardSummary from 'models/results/award/AwardSummary'; import { mockAward } from './mockAward'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - // spy on specific functions inside the component const getAwardSpy = sinon.spy(AwardContainer.prototype, 'getSelectedAward'); @@ -24,70 +19,37 @@ const parameters = { awardId: 57557 }; +jest.mock('helpers/searchHelper', () => require('../search/filters/searchHelper')); + // mock the child component by replacing it with a function that returns a null element jest.mock('components/award/Award', () => jest.fn(() => null)); -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('AwardContainer', () => { - it('should make an API call for the selected award on mount', () => { - // Mock the api call - mockSearchHelper('fetchAward', 'resolve', mockAward); - + it('should make an API call for the selected award on mount', async () => { // mount the container - mount(); + const container = mount( + ); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().awardRequest.promise; // checking that it ran expect(getAwardSpy.callCount).toEqual(1); // reset the spies - unmockSearchHelper(); getAwardSpy.reset(); }); - it('should make an API call when the award ID parameter changes', () => { - // Mock the api call - mockSearchHelper('fetchAward', 'resolve', mockAward); - + it('should make an API call when the award ID parameter changes', async () => { // mount the container - const container = mount(); + const container = mount( + ); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().awardRequest.promise; // checking that it ran expect(getAwardSpy.callCount).toEqual(1); @@ -98,11 +60,9 @@ describe('AwardContainer', () => { } }); - jest.runAllTicks(); expect(getAwardSpy.callCount).toEqual(2); // reset the spies - unmockSearchHelper(); getAwardSpy.reset(); }); diff --git a/tests/containers/award/table/ContractTransactionsTableContainer-test.jsx b/tests/containers/award/table/ContractTransactionsTableContainer-test.jsx index de050fdb95..bdfdc7b8bb 100644 --- a/tests/containers/award/table/ContractTransactionsTableContainer-test.jsx +++ b/tests/containers/award/table/ContractTransactionsTableContainer-test.jsx @@ -86,7 +86,8 @@ describe('ContractTransactionsTableContainer', () => { const container = mount(); + award={mockAward} + appendAwardTransactions={jest.fn()} />); jest.runAllTicks(); @@ -173,7 +174,8 @@ describe('ContractTransactionsTableContainer', () => { const container = shallow(); + award={modifiedProps} + appendAwardTransactions={jest.fn()} />); container.instance().nextTransactionPage(); expect(loadDataSpy.withArgs(2).callCount).toBe(1); @@ -191,7 +193,8 @@ describe('ContractTransactionsTableContainer', () => { const container = shallow(); + award={modifiedProps} + appendAwardTransactions={jest.fn()} />); container.instance().nextTransactionPage(); expect(loadDataSpy.notCalled).toBeTruthy(); @@ -210,7 +213,8 @@ describe('ContractTransactionsTableContainer', () => { const container = shallow(); + award={modifiedProps} + appendAwardTransactions={jest.fn()} />); const output = container.instance().formatSort(); expect(output).toEqual('-field'); diff --git a/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx b/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx index 6c4bd61d84..34bf747b4c 100644 --- a/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx +++ b/tests/containers/search/filters/recipientFilter/RecipientLocationContainer-test.jsx @@ -3,11 +3,6 @@ * Created by michaelbray on 2/17/17. */ -jest.mock('helpers/searchHelper', () => { - const helper = require('./mocks/searchHelper'); - return helper; -}); - import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; @@ -24,6 +19,8 @@ const initialFilters = { autocompleteRecipientLocations: [] }; +jest.mock('helpers/searchHelper', () => require('../searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; describe('RecipientLocationContainer', () => { describe('Handling text input', () => { diff --git a/tests/containers/search/filters/recipientFilter/mocks/searchHelper.js b/tests/containers/search/filters/recipientFilter/mocks/searchHelper.js deleted file mode 100644 index d9755903a7..0000000000 --- a/tests/containers/search/filters/recipientFilter/mocks/searchHelper.js +++ /dev/null @@ -1,15 +0,0 @@ -import { mockLocationAutocomplete } from './mockRecipient'; - -// Location search for autocomplete -export const fetchLocations = () => ( - { - promise: new Promise((resolve) => { - process.nextTick(() => { - resolve({ - data: mockLocationAutocomplete - }); - }); - }), - cancel: jest.fn() - } -); diff --git a/tests/containers/search/filters/searchHelper.js b/tests/containers/search/filters/searchHelper.js new file mode 100644 index 0000000000..98a4751c65 --- /dev/null +++ b/tests/containers/search/filters/searchHelper.js @@ -0,0 +1,76 @@ +import { mockLocationAutocomplete } from '../../../redux/reducers/search/mock/mockRecipient'; +import { mockAwardResponse } from '../../../redux/reducers/award/mockAward'; +import { accountProgramActivities } + from '../../../redux/reducers/account/mockAccountProgramActivities'; +import { spendingByCategory, geo } + from '../../../containers/search/visualizations/mockVisualizations'; + +// Fetch Locations for Autocomplete +export const fetchLocations = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockLocationAutocomplete + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Individual Awards +export const fetchAward = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockAwardResponse + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Program Activities +export const fetchProgramActivities = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: accountProgramActivities + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Categories +export const performCategorySearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: spendingByCategory + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Transactions Total for Geo +export const performTransactionsTotalSearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: geo + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx b/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx index 46478c1039..6f06c8a495 100644 --- a/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx +++ b/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx @@ -11,56 +11,19 @@ import { Set } from 'immutable'; import { GeoVisualizationSectionContainer } from 'containers/search/visualizations/geo/GeoVisualizationSectionContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; +jest.mock('helpers/searchHelper', () => require('../../filters/searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + // mock the child component by replacing it with a function that returns a null element jest.mock('components/search/visualizations/geo/GeoVisualizationSection', () => jest.fn(() => null)); - -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - // spy on specific functions inside the component const fetchDataSpy = sinon.spy(GeoVisualizationSectionContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - const mockedReduxMeta = { visualization: { transaction_sum: 50000 @@ -68,72 +31,22 @@ const mockedReduxMeta = { }; describe('GeoVisualizationSectionContainer', () => { - it('should make an API request on mount', () => { - const apiResponse = { - results: [ - { - item: 'AK', - aggregate: '123.12' - }, - { - item: 'AL', - aggregate: '345.56' - } - ], - total_metadata: { - count: 2 - }, - page_metadata: { - page_number: 1, - count: 2, - num_pages: 1 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container - mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - const apiResponse = { - results: [ - { - item: 'AK', - aggregate: '123.12' - }, - { - item: 'AL', - aggregate: '345.56' - } - ], - total_metadata: { - count: 2 - }, - page_metadata: { - page_number: 1, - count: 2, - num_pages: 1 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -146,8 +59,7 @@ describe('GeoVisualizationSectionContainer', () => { reduxFilters={initialFilters} resultsMeta={mockedReduxMeta} />); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -162,44 +74,18 @@ describe('GeoVisualizationSectionContainer', () => { // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly resture the API response for the map visualization', () => { - const apiResponse = { - results: [ - { - item: 'AK', - aggregate: '123.12' - }, - { - item: 'AL', - aggregate: '345.56' - } - ], - total_metadata: { - count: 2 - }, - page_metadata: { - page_number: 1, - count: 2, - num_pages: 1 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should properly resture the API response for the map visualization', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; const expectedState = { data: { @@ -215,6 +101,9 @@ describe('GeoVisualizationSectionContainer', () => { delete actualState.renderHash; expect(actualState).toEqual(expectedState); + + // reset the spy + fetchDataSpy.reset(); }); }); diff --git a/tests/containers/search/visualizations/mockVisualizations.js b/tests/containers/search/visualizations/mockVisualizations.js new file mode 100644 index 0000000000..dbbf9d3eb3 --- /dev/null +++ b/tests/containers/search/visualizations/mockVisualizations.js @@ -0,0 +1,40 @@ +export const spendingByCategory = { + page_metadata: { + page: 1, + has_next_page: false, + has_previous_page: false, + next: null, + previous: null + }, + results: [ + { + treasury_account__budget_function_title: 'First Budget Function', + aggregate: '456' + }, + { + treasury_account__budget_function_title: 'Second Budget Function', + aggregate: '123' + } + ] +}; + +export const geo = { + results: [ + { + item: 'AK', + aggregate: '123.12' + }, + { + item: 'AL', + aggregate: '345.56' + } + ], + total_metadata: { + count: 2 + }, + page_metadata: { + page_number: 1, + count: 2, + num_pages: 1 + } +}; diff --git a/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx index f7d5a96d0e..ef0781dc32 100644 --- a/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx @@ -13,53 +13,17 @@ import { SpendingByCategoryRankVisualizationSectionContainer } from 'containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer'; import SpendingByCategorySection from 'components/search/visualizations/rank/sections/SpendingByCategorySection'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('../../filters/searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const fetchDataSpy = sinon.spy(SpendingByCategoryRankVisualizationSectionContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('SpendingByCategoryRankVisualizationSectionContainer', () => { beforeAll(() => { // we need to use mount() on the container to get the lifecycle logic, but enzyme doesn't @@ -69,38 +33,13 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { mockComponent(SpendingByCategorySection); }); - it('should make an API request on mount', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - treasury_account__budget_function_title: 'First Budget Function', - aggregate: '456' - }, - { - treasury_account__budget_function_title: 'Second Budget Function', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); @@ -108,36 +47,11 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { // the page number should be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - treasury_account__budget_function_title: 'First Budget Function', - aggregate: '456' - }, - { - treasury_account__budget_function_title: 'Second Budget Function', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -149,8 +63,7 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { mount(); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -163,51 +76,25 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); // the page number should still be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly restructure the API data for the rank visualization', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - treasury_account__budget_function_title: 'First Budget Function', - aggregate: '456' - }, - { - treasury_account__budget_function_title: 'Second Budget Function', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); + it('should properly restructure the API data for the rank visualization', async () => { // mount the container const container = mount(); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); + await container.instance().apiRequest.promise; + // validate the state contains the correctly parsed values const expectedState = { loading: false, @@ -230,35 +117,14 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { }); describe('nextPage', () => { - it('should trigger a new API call with an incremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - treasury_account__budget_function_title: 'First Budget Function', - aggregate: '456' - }, - { - treasury_account__budget_function_title: 'Second Budget Function', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); + it('should trigger a new API call with an incremented page number', async () => { // mount the container const container = mount(); + await container.instance().apiRequest.promise; + // initial state should be page 1 expect(container.state().page).toEqual(1); @@ -274,42 +140,20 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { }); describe('previousPage', () => { - it('should trigger a new API call with a decremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - treasury_account__budget_function_title: 'First Budget Function', - aggregate: '456' - }, - { - treasury_account__budget_function_title: 'Second Budget Function', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); + it('should trigger a new API call with a decremented page number', async () => { // mount the container const container = mount(); + + await container.instance().apiRequest.promise; + container.setState({ page: 5, has_previous_page: true, previous: "checksum" }); - // wait for the SearchHelper promises to resolve - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(5); @@ -318,34 +162,14 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { expect(container.state().page).toEqual(4); }); - it('should never use a page number less than 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - treasury_account__budget_function_title: 'First Budget Function', - aggregate: '456' - }, - { - treasury_account__budget_function_title: 'Second Budget Function', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); + it('should never use a page number less than 1', async () => { // mount the container const container = mount(); + + await container.instance().apiRequest.promise; + container.setState({ page: 1 }); diff --git a/tests/redux/reducers/account/mockAccountProgramActivities.js b/tests/redux/reducers/account/mockAccountProgramActivities.js new file mode 100644 index 0000000000..7ff4203f3f --- /dev/null +++ b/tests/redux/reducers/account/mockAccountProgramActivities.js @@ -0,0 +1,7 @@ +export const accountProgramActivities = { + aggregate: "2.00", + item: "Veterans employment and training", + program_activity__id: "11694", + program_activity__program_activity_code: "0020", + program_activity__program_activity_name: "Veterans employment and training", +}; diff --git a/tests/redux/reducers/search/mock/mockFilters.js b/tests/redux/reducers/search/mock/mockFilters.js index e882f53c06..d4456c8a7b 100644 --- a/tests/redux/reducers/search/mock/mockFilters.js +++ b/tests/redux/reducers/search/mock/mockFilters.js @@ -168,3 +168,4 @@ export const mockAgency = { office_agency: null, agencyType: 'subtier' }; + diff --git a/tests/containers/search/filters/recipientFilter/mocks/mockRecipient.js b/tests/redux/reducers/search/mock/mockRecipient.js similarity index 100% rename from tests/containers/search/filters/recipientFilter/mocks/mockRecipient.js rename to tests/redux/reducers/search/mock/mockRecipient.js From 5710651a1f17770a5a89ba37c19780a328f12982 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Sun, 16 Jul 2017 20:31:36 -0400 Subject: [PATCH 20/97] Moving individual visualizations to their own helpers --- .../containers/search/filters/searchHelper.js | 33 +-------------- .../GeoVisualizationSectionContainer-test.jsx | 4 +- .../visualizations/geo/mocks/geoHelper.js | 15 +++++++ ...RankVisualizationSectionContainer-test.jsx | 2 +- ...ndustryCodeVisualizationContainer-test.jsx | 40 +------------------ .../rank/mocks/awardingAgencyHelper.js | 3 ++ .../rank/mocks/categoryHelper.js | 15 +++++++ .../visualizations/rank/mocks/cdfaHelper.js | 3 ++ .../rank/mocks/fundingAgencyHelper.js | 3 ++ .../rank/mocks/industryCodeHelper.js | 3 ++ .../rank/mocks/recipientHelper.js | 3 ++ 11 files changed, 51 insertions(+), 73 deletions(-) create mode 100644 tests/containers/search/visualizations/geo/mocks/geoHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/categoryHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/cdfaHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/recipientHelper.js diff --git a/tests/containers/search/filters/searchHelper.js b/tests/containers/search/filters/searchHelper.js index 98a4751c65..1ffb122cee 100644 --- a/tests/containers/search/filters/searchHelper.js +++ b/tests/containers/search/filters/searchHelper.js @@ -2,8 +2,7 @@ import { mockLocationAutocomplete } from '../../../redux/reducers/search/mock/mo import { mockAwardResponse } from '../../../redux/reducers/award/mockAward'; import { accountProgramActivities } from '../../../redux/reducers/account/mockAccountProgramActivities'; -import { spendingByCategory, geo } - from '../../../containers/search/visualizations/mockVisualizations'; + // Fetch Locations for Autocomplete export const fetchLocations = () => ( @@ -45,32 +44,4 @@ export const fetchProgramActivities = () => ( }), cancel: jest.fn() } -); - -// Fetch Categories -export const performCategorySearch = () => ( - { - promise: new Promise((resolve) => { - process.nextTick(() => { - resolve({ - data: spendingByCategory - }); - }); - }), - cancel: jest.fn() - } -); - -// Fetch Transactions Total for Geo -export const performTransactionsTotalSearch = () => ( - { - promise: new Promise((resolve) => { - process.nextTick(() => { - resolve({ - data: geo - }); - }); - }), - cancel: jest.fn() - } -); +); \ No newline at end of file diff --git a/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx b/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx index 6f06c8a495..59f4ccfd00 100644 --- a/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx +++ b/tests/containers/search/visualizations/geo/GeoVisualizationSectionContainer-test.jsx @@ -14,7 +14,7 @@ import { GeoVisualizationSectionContainer } from import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; -jest.mock('helpers/searchHelper', () => require('../../filters/searchHelper')); +jest.mock('helpers/searchHelper', () => require('./mocks/geoHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // mock the child component by replacing it with a function that returns a null element @@ -69,8 +69,6 @@ describe('GeoVisualizationSectionContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); diff --git a/tests/containers/search/visualizations/geo/mocks/geoHelper.js b/tests/containers/search/visualizations/geo/mocks/geoHelper.js new file mode 100644 index 0000000000..a3ff92c27c --- /dev/null +++ b/tests/containers/search/visualizations/geo/mocks/geoHelper.js @@ -0,0 +1,15 @@ +import { geo } from '../../mockVisualizations'; + +// Fetch Transactions Total for Geo +export const performTransactionsTotalSearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: geo + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx index ef0781dc32..4d0d5a0545 100644 --- a/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByCategoryRankVisualizationSectionContainer-test.jsx @@ -17,7 +17,7 @@ import SpendingByCategorySection from import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -jest.mock('helpers/searchHelper', () => require('../../filters/searchHelper')); +jest.mock('helpers/searchHelper', () => require('./mocks/categoryHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component diff --git a/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx index e8b755caac..e36b44e693 100644 --- a/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx @@ -13,53 +13,17 @@ import { SpendingByIndustryCodeVisualizationContainer } from 'containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer'; import SpendingByIndustryCodeSection from 'components/search/visualizations/rank/sections/SpendingByIndustryCodeSection'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('../../filters/searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const fetchDataSpy = sinon.spy(SpendingByIndustryCodeVisualizationContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('SpendingByIndustryCodeVisualizationContainer', () => { beforeAll(() => { // we need to use mount() on the container to get the lifecycle logic, but enzyme doesn't diff --git a/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js b/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js new file mode 100644 index 0000000000..eb4f7d9f9c --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js @@ -0,0 +1,3 @@ +/** + * Created by michaelbray on 7/16/17. + */ diff --git a/tests/containers/search/visualizations/rank/mocks/categoryHelper.js b/tests/containers/search/visualizations/rank/mocks/categoryHelper.js new file mode 100644 index 0000000000..d4d505013a --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/categoryHelper.js @@ -0,0 +1,15 @@ +import { spendingByCategory } from '../../mockVisualizations'; + +// Fetch Categories +export const performCategorySearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: spendingByCategory + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/search/visualizations/rank/mocks/cdfaHelper.js b/tests/containers/search/visualizations/rank/mocks/cdfaHelper.js new file mode 100644 index 0000000000..eb4f7d9f9c --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/cdfaHelper.js @@ -0,0 +1,3 @@ +/** + * Created by michaelbray on 7/16/17. + */ diff --git a/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js b/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js new file mode 100644 index 0000000000..eb4f7d9f9c --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js @@ -0,0 +1,3 @@ +/** + * Created by michaelbray on 7/16/17. + */ diff --git a/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js b/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js new file mode 100644 index 0000000000..eb4f7d9f9c --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js @@ -0,0 +1,3 @@ +/** + * Created by michaelbray on 7/16/17. + */ diff --git a/tests/containers/search/visualizations/rank/mocks/recipientHelper.js b/tests/containers/search/visualizations/rank/mocks/recipientHelper.js new file mode 100644 index 0000000000..eb4f7d9f9c --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/recipientHelper.js @@ -0,0 +1,3 @@ +/** + * Created by michaelbray on 7/16/17. + */ From 9bde9b9b03e9121ced25c9c4a91153ca968131c0 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Sun, 16 Jul 2017 20:36:31 -0400 Subject: [PATCH 21/97] Fixing Industry Codes tests --- .../visualizations/mockVisualizations.js | 22 +++ ...ndustryCodeVisualizationContainer-test.jsx | 158 ++---------------- .../rank/mocks/industryCodeHelper.js | 18 +- 3 files changed, 54 insertions(+), 144 deletions(-) diff --git a/tests/containers/search/visualizations/mockVisualizations.js b/tests/containers/search/visualizations/mockVisualizations.js index dbbf9d3eb3..7b80036f30 100644 --- a/tests/containers/search/visualizations/mockVisualizations.js +++ b/tests/containers/search/visualizations/mockVisualizations.js @@ -38,3 +38,25 @@ export const geo = { num_pages: 1 } }; + +export const industryCode = { + page_metadata: { + page: 1, + has_next_page: false, + has_previous_page: false, + next: null, + previous: null + }, + results: [ + { + item: '1234', + aggregate: '500.00', + contract_data__product_or_service_code: '1234' + }, + { + item: '2345', + aggregate: '400.01', + contract_data__product_or_service_code: '2345' + } + ] +} \ No newline at end of file diff --git a/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx index e36b44e693..c577a76539 100644 --- a/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByIndustryCodeVisualizationContainer-test.jsx @@ -17,7 +17,7 @@ import SpendingByIndustryCodeSection from import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -jest.mock('helpers/searchHelper', () => require('../../filters/searchHelper')); +jest.mock('helpers/searchHelper', () => require('./mocks/industryCodeHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component @@ -33,40 +33,13 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { mockComponent(SpendingByIndustryCodeSection); }); - it('should make an API request on mount', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: '1234', - aggregate: '500.00', - contract_data__product_or_service_code: '1234' - }, - { - item: '2345', - aggregate: '400.01', - contract_data__product_or_service_code: '2345' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); @@ -74,38 +47,11 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { // the page number should be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: '1234', - aggregate: '500.00', - award__transaction__contract_data__product_or_service_code: '1234' - }, - { - item: '2345', - aggregate: '400.01', - award__transaction__contract_data__product_or_service_code: '2345' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performFinancialAccountAggregation', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -117,8 +63,7 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { mount(); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -131,53 +76,25 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); // the page number should still be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly restructure the API data for the rank visualization', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: '1234', - aggregate: '500.00', - contract_data__product_or_service_code: '1234' - }, - { - item: '2345', - aggregate: '400.01', - contract_data__product_or_service_code: '2345' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); + it('should properly restructure the API data for the rank visualization', async () => { // mount the container const container = mount(); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); + await container.instance().apiRequest.promise; + // validate the state contains the correctly parsed values const expectedState = { loading: false, @@ -200,20 +117,6 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { describe('nextPage', () => { it('should trigger a new API call with an incremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount( { describe('previousPage', () => { it('should trigger a new API call with a decremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount( { previous: "checksum" }); - // wait for the SearchHelper promises to resolve - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(5); @@ -270,30 +157,15 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { }); it('should never use a page number less than 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount(); + container.setState({ page: 1 }); - // wait for the SearchHelper promises to resolve - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(1); @@ -304,7 +176,7 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { }); describe('newSearch', () => { - it('when Redux filters change, the page number should reset to 1', () => { + it('when Redux filters change, the page number should reset to 1', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -315,12 +187,15 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { const container = mount(); + container.setState({ page: 5, has_previous_page: true, previous: "checksum" }); + await container.instance().apiRequest.promise; + // assume we are starting on page 5 expect(container.state().page).toEqual(5); @@ -348,10 +223,11 @@ describe('SpendingByIndustryCodeVisualizationContainer', () => { expect(container.state().scope).toEqual('naics'); }); - it('should reset the page number to 1 when the scope changes', () => { + it('should reset the page number to 1 when the scope changes', async () => { const container = mount(); + container.setState({ page: 5 }); diff --git a/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js b/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js index eb4f7d9f9c..dd508ead8b 100644 --- a/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js +++ b/tests/containers/search/visualizations/rank/mocks/industryCodeHelper.js @@ -1,3 +1,15 @@ -/** - * Created by michaelbray on 7/16/17. - */ +import { industryCode } from '../../mockVisualizations'; + +// Fetch Industry Codes +export const performTransactionsTotalSearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: industryCode + }); + }); + }), + cancel: jest.fn() + } +); From 7d37b5af089c150bd5ea7799ed392351a0c08fc6 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Sun, 16 Jul 2017 20:44:01 -0400 Subject: [PATCH 22/97] Fixing Recipient visualization tests --- .../visualizations/mockVisualizations.js | 74 ++++-- ...ByRecipientVisualizationContainer-test.jsx | 221 ++---------------- .../rank/mocks/recipientHelper.js | 18 +- 3 files changed, 82 insertions(+), 231 deletions(-) diff --git a/tests/containers/search/visualizations/mockVisualizations.js b/tests/containers/search/visualizations/mockVisualizations.js index 7b80036f30..8942b2855b 100644 --- a/tests/containers/search/visualizations/mockVisualizations.js +++ b/tests/containers/search/visualizations/mockVisualizations.js @@ -1,3 +1,28 @@ +export const geo = { + results: [ + { + item: 'AK', + aggregate: '123.12' + }, + { + item: 'AL', + aggregate: '345.56' + } + ], + total_metadata: { + count: 2 + }, + page_metadata: { + page_number: 1, + count: 2, + num_pages: 1 + } +}; + +export const awardingAgency = { + +}; + export const spendingByCategory = { page_metadata: { page: 1, @@ -18,25 +43,12 @@ export const spendingByCategory = { ] }; -export const geo = { - results: [ - { - item: 'AK', - aggregate: '123.12' - }, - { - item: 'AL', - aggregate: '345.56' - } - ], - total_metadata: { - count: 2 - }, - page_metadata: { - page_number: 1, - count: 2, - num_pages: 1 - } +export const cfda = { + +}; + +export const fundingAgency = { + }; export const industryCode = { @@ -59,4 +71,26 @@ export const industryCode = { contract_data__product_or_service_code: '2345' } ] -} \ No newline at end of file +}; + +export const recipient = { + page_metadata: { + page: 1, + has_next_page: false, + has_previous_page: false, + next: null, + previous: null + }, + results: [ + { + recipient__legal_entity_id: '1', + recipient__recipient_name: 'Multiple Recipients', + aggregate: '149620471458.92' + }, + { + recipient__legal_entity_id: '113704139', + recipient__recipient_name: 'Michigan', + aggregate: '6684225478.00' + } + ] +}; diff --git a/tests/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer-test.jsx index 6241c7f03a..91cf424a7c 100644 --- a/tests/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer-test.jsx @@ -13,54 +13,18 @@ import { SpendingByRecipientVisualizationContainer } from 'containers/search/visualizations/rank/SpendingByRecipientVisualizationContainer'; import SpendingByRecipientSection from 'components/search/visualizations/rank/sections/SpendingByRecipientSection'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('./mocks/recipientHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const fetchDataSpy = sinon.spy(SpendingByRecipientVisualizationContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - -describe('SpendingByCategoryRankVisualizationSectionContainer', () => { +describe('SpendingByRecipientVisualizationContainer', () => { beforeAll(() => { // we need to use mount() on the container to get the lifecycle logic, but enzyme doesn't // support the child component's SVG manipulation methods. This replaces all the child @@ -69,40 +33,13 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { mockComponent(SpendingByRecipientSection); }); - it('should make an API request on mount', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - recipient__legal_entity_id: '1', - recipient__recipient_name: 'Multiple Recipients', - aggregate: '149620471458.92' - }, - { - recipient__legal_entity_id: '113704139', - recipient__recipient_name: 'Michigan', - aggregate: '6684225478.00' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); @@ -110,38 +47,11 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { // the page number should be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - recipient__legal_entity_id: '1', - recipient__recipient_name: 'Multiple Recipients', - aggregate: '149620471458.92' - }, - { - recipient__legal_entity_id: '113704139', - recipient__recipient_name: 'Michigan', - aggregate: '6684225478.00' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -153,8 +63,7 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { mount(); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -167,53 +76,25 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); // the page number should still be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly restructure the API data for the rank visualization', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - recipient__legal_entity_id: '1', - recipient__recipient_name: 'Multiple Recipients', - aggregate: '149620471458.92' - }, - { - recipient__legal_entity_id: '113704139', - recipient__recipient_name: 'Michigan', - aggregate: '6684225478.00' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); + it('should properly restructure the API data for the rank visualization', async () => { // mount the container const container = mount(); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); + await container.instance().apiRequest.promise; + // validate the state contains the correctly parsed values const expectedState = { loading: false, @@ -237,31 +118,6 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { describe('nextPage', () => { it('should trigger a new API call with an incremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - recipient__legal_entity_id: '1', - recipient__recipient_name: 'Multiple Recipients', - aggregate: '149620471458.92' - }, - { - recipient__legal_entity_id: '113704139', - recipient__recipient_name: 'Michigan', - aggregate: '6684225478.00' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount( { describe('previousPage', () => { it('should trigger a new API call with a decremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - recipient__legal_entity_id: '1', - recipient__recipient_name: 'Multiple Recipients', - aggregate: '149620471458.92' - }, - { - recipient__legal_entity_id: '113704139', - recipient__recipient_name: 'Michigan', - aggregate: '6684225478.00' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount(); + container.setState({ page: 5, has_previous_page: true, previous: "checksum" }); - // wait for the SearchHelper promises to resolve - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(5); @@ -329,31 +159,6 @@ describe('SpendingByCategoryRankVisualizationSectionContainer', () => { }); it('should never use a page number less than 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - recipient__legal_entity_id: '1', - recipient__recipient_name: 'Multiple Recipients', - aggregate: '149620471458.92' - }, - { - recipient__legal_entity_id: '113704139', - recipient__recipient_name: 'Michigan', - aggregate: '6684225478.00' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount( ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: recipient + }); + }); + }), + cancel: jest.fn() + } +); From cea6875ee4a3488f24d4260a288a8ec22f397958 Mon Sep 17 00:00:00 2001 From: Michael Bray Date: Mon, 17 Jul 2017 15:44:39 -0400 Subject: [PATCH 23/97] Finished all test upgrades except ResultsTableContainer --- package.json | 2 +- .../account/AccountContainer-test.jsx | 63 +- tests/containers/account/accountHelper.js | 44 ++ .../AccountProgramActivityContainer-test.jsx | 2 +- .../filters}/mockAccountProgramActivities.js | 2 +- .../containers/award/AwardContainer-test.jsx | 2 +- tests/containers/award/awardHelper.js | 15 + tests/containers/award/mockAward.js | 179 +++++ .../agencyFilter/AgencyListContainer-test.jsx | 140 +--- .../filters/agencyFilter/mockAgencies.js | 45 ++ .../awardID/AwardIDListContainer-test.jsx | 628 +----------------- .../search/filters/awardID/mockAwardIDs.js | 550 +++++++++++++++ .../BudgetCategoryAccountContainer-test.jsx | 86 +-- .../BudgetCategoryFunctionContainer-test.jsx | 78 +-- .../budgetCategory/mockBudgetCategories.js | 20 + .../RecipientNameDUNSContainer-test.jsx | 209 +----- .../filters/recipientFilter/mockRecipients.js | 159 +++++ .../containers/search/filters/searchHelper.js | 97 ++- .../table/ResultsTableContainer-test.jsx | 225 +++---- .../visualizations/mockVisualizations.js | 58 +- ...rdingAgencyVisualizationContainer-test.jsx | 268 +------- ...ndingByCFDAVisualizationContainer-test.jsx | 196 +----- ...ndingAgencyVisualizationContainer-test.jsx | 239 +------ .../rank/mocks/awardingAgencyHelper.js | 18 +- .../visualizations/rank/mocks/cdfaHelper.js | 3 - .../visualizations/rank/mocks/cfdaHelper.js | 15 + .../rank/mocks/fundingAgencyHelper.js | 18 +- .../reducers/search/mock/mockRecipient.js | 6 - 28 files changed, 1440 insertions(+), 1927 deletions(-) create mode 100644 tests/containers/account/accountHelper.js rename tests/{redux/reducers/account => containers/account/filters}/mockAccountProgramActivities.js (83%) create mode 100644 tests/containers/award/awardHelper.js create mode 100644 tests/containers/search/filters/agencyFilter/mockAgencies.js create mode 100644 tests/containers/search/filters/awardID/mockAwardIDs.js create mode 100644 tests/containers/search/filters/budgetCategory/mockBudgetCategories.js create mode 100644 tests/containers/search/filters/recipientFilter/mockRecipients.js delete mode 100644 tests/containers/search/visualizations/rank/mocks/cdfaHelper.js create mode 100644 tests/containers/search/visualizations/rank/mocks/cfdaHelper.js delete mode 100644 tests/redux/reducers/search/mock/mockRecipient.js diff --git a/package.json b/package.json index 7f50676e76..02079ff0b6 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "react-dom": "^15.6.0", "react-test-renderer": "^15.6.0", "sass-loader": "^6.0.6", - "sinon": "^2.3.5", + "sinon": "^2.3.8", "style-loader": "^0.18.2", "webpack": "^2.6.1", "webpack-bundle-analyzer": "^2.8.2", diff --git a/tests/containers/account/AccountContainer-test.jsx b/tests/containers/account/AccountContainer-test.jsx index 1eba6b445d..9dc69381f9 100644 --- a/tests/containers/account/AccountContainer-test.jsx +++ b/tests/containers/account/AccountContainer-test.jsx @@ -8,14 +8,12 @@ import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; import { AccountContainer } from 'containers/account/AccountContainer'; -import * as AccountHelper from 'helpers/accountHelper'; import FederalAccount from 'models/account/FederalAccount'; import { mockAccount, mockBalances, mockReduxAccount } from './mockAccount'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/accountHelper', () => require('./accountHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const loadAccountSpy = sinon.spy(AccountContainer.prototype, 'loadData'); @@ -37,64 +35,28 @@ jest.mock('containers/glossary/GlossaryButtonWrapperContainer', () => jest.mock('containers/glossary/GlossaryContainer', () => jest.fn(() => null)); -const mockAccountHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - AccountHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockAccountHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/accountHelper'); -}; - describe('AccountContainer', () => { - it('should make an API call for the selected account on mount', () => { - mockAccountHelper('fetchFederalAccount', 'resolve', mockAccount); - mockAccountHelper('fetchTasBalanceTotals', 'resolve', mockBalances.outlay); - + it('should make an API call for the selected account on mount', async () => { const mockRedux = { account: mockReduxAccount }; - mount(); - jest.runAllTicks(); + await container.instance().accountRequest.promise; + await container.instance().balanceRequests.promise; expect(loadAccountSpy.callCount).toEqual(1); expect(loadBalancesSpy.callCount).toEqual(1); + loadAccountSpy.reset(); loadBalancesSpy.reset(); }); - it('should make an API call when the award ID parameter changes', () => { - mockAccountHelper('fetchFederalAccount', 'resolve', mockAccount); - mockAccountHelper('fetchTasBalanceTotals', 'resolve', mockBalances.outlay); - + it('should make an API call when the award ID parameter changes', async () => { const mockRedux = { account: mockReduxAccount }; @@ -104,7 +66,9 @@ describe('AccountContainer', () => { setSelectedAccount={jest.fn()} account={mockRedux} />); - jest.runAllTicks(); + await container.instance().accountRequest.promise; + await container.instance().balanceRequests.promise; + expect(loadAccountSpy.callCount).toEqual(1); expect(loadBalancesSpy.callCount).toEqual(1); @@ -114,9 +78,12 @@ describe('AccountContainer', () => { } }); - jest.runAllTicks(); + await container.instance().accountRequest.promise; + await container.instance().balanceRequests.promise; + expect(loadAccountSpy.callCount).toEqual(2); expect(loadBalancesSpy.callCount).toEqual(2); + loadAccountSpy.reset(); loadBalancesSpy.reset(); }); diff --git a/tests/containers/account/accountHelper.js b/tests/containers/account/accountHelper.js new file mode 100644 index 0000000000..fa3de8a068 --- /dev/null +++ b/tests/containers/account/accountHelper.js @@ -0,0 +1,44 @@ +import { mockAccountProgramActivities } from './filters/mockAccountProgramActivities'; +import { mockAccount, mockBalances } from './mockAccount'; + +// Fetch Program Activities +export const fetchProgramActivities = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockAccountProgramActivities + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Federal Accounts +export const fetchFederalAccount = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockAccount + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch TAS Balances +export const fetchTasBalanceTotals = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockBalances.outlay + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx b/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx index fb7451e416..3b0df486a1 100644 --- a/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx +++ b/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx @@ -23,7 +23,7 @@ const account = { id: 2525 }; -jest.mock('helpers/searchHelper', () => require('../../search/filters/searchHelper')); +jest.mock('helpers/searchHelper', () => require('../accountHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; describe('AccountProgramActivityContainer', () => { diff --git a/tests/redux/reducers/account/mockAccountProgramActivities.js b/tests/containers/account/filters/mockAccountProgramActivities.js similarity index 83% rename from tests/redux/reducers/account/mockAccountProgramActivities.js rename to tests/containers/account/filters/mockAccountProgramActivities.js index 7ff4203f3f..fa77ed7e4d 100644 --- a/tests/redux/reducers/account/mockAccountProgramActivities.js +++ b/tests/containers/account/filters/mockAccountProgramActivities.js @@ -1,4 +1,4 @@ -export const accountProgramActivities = { +export const mockAccountProgramActivities = { aggregate: "2.00", item: "Veterans employment and training", program_activity__id: "11694", diff --git a/tests/containers/award/AwardContainer-test.jsx b/tests/containers/award/AwardContainer-test.jsx index 246377cd83..b63d2128db 100644 --- a/tests/containers/award/AwardContainer-test.jsx +++ b/tests/containers/award/AwardContainer-test.jsx @@ -19,7 +19,7 @@ const parameters = { awardId: 57557 }; -jest.mock('helpers/searchHelper', () => require('../search/filters/searchHelper')); +jest.mock('helpers/searchHelper', () => require('./awardHelper')); // mock the child component by replacing it with a function that returns a null element jest.mock('components/award/Award', () => diff --git a/tests/containers/award/awardHelper.js b/tests/containers/award/awardHelper.js new file mode 100644 index 0000000000..bea8dbd325 --- /dev/null +++ b/tests/containers/award/awardHelper.js @@ -0,0 +1,15 @@ +import { mockAwards } from './mockAward'; + +// Fetch Individual Awards +export const fetchAward = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockAwards + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/award/mockAward.js b/tests/containers/award/mockAward.js index ad31bb8a92..c17e41a646 100644 --- a/tests/containers/award/mockAward.js +++ b/tests/containers/award/mockAward.js @@ -408,3 +408,182 @@ export const mockAward = { direction: 'desc' } }; + +export const mockAwards = { + total_metadata: { + count: 2 + }, + page_metadata: { + page: 1, + has_next_page: true + }, + results: [ + { + financial_accounts_by_awards_id: 1, + program_activity_name: 'Reimbursable program activity', + certified_date: null, + treasury_account: { + treasury_account_identifier: 69481, + tas_rendering_label: '0892017/20180228', + account_title: 'Departmental Administration, Energy Programs, Energy', + reporting_agency_id: '089', + reporting_agency_name: 'Department of Energy' + }, + program_activity_code: 801, + object_class: '254', + transaction_obligations: [{ + transaction_obligated_amount: '-323015.00' + }] + }, { + financial_accounts_by_awards_id: 2, + program_activity_name: 'Wind Energy', + certified_date: null, + treasury_account: { + treasury_account_identifier: 35975, + tas_rendering_label: '089X0321', + account_title: 'Energy Efficiency and Renewable Energy, Energy Programs, Energy', + reporting_agency_id: '089', + reporting_agency_name: 'Department of Energy' + }, + program_activity_code: 102, + object_class: '254', + transaction_obligations: [{ + transaction_obligated_amount: '-11522.00' + }] + } + ] +}; + +export const mockTransactions = [ + { + id: 40904, + type: 'D', + type_description: 'Unknown Type', + action_date: '11/30/2016', + action_type: 'C', + federal_action_obligation: '$4,437,307', + modification_number: '959', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - TAS::97 4555::TAS - OBLIGATE SPP DOD FUNDING - NOVEMBER 30 2016' + }, + { + id: 40905, + type: 'D', + type_description: 'Unknown Type', + action_date: '11/30/2016', + action_type: 'C', + federal_action_obligation: '$9,740,762', + modification_number: '958', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $9,740,762.00 IN DOE APPROPRIATED FUNDING AND $4,278,014.31 IN NON-APPROPRIATED FUNDS; CUMULATIVE NA FUNDS - $435,532,331.16.' + }, + { + id: 40906, + type: 'D', + type_description: 'Unknown Type', + action_date: '11/17/2016', + action_type: 'C', + federal_action_obligation: '$241,000', + modification_number: '957', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $241,000.00 IN DOE APPROPRIATED FUNDING AND $0.00 IN NON-APPROPRIATED FUNDS; CUMULATIVE NA FUNDS - $431,254,316.85.' + }, + { + id: 40907, + type: 'D', + type_description: 'Unknown Type', + action_date: '11/10/2016', + action_type: 'C', + federal_action_obligation: '$40,000', + modification_number: '956', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $40,000.00 IN DOE APPROPRIATED FUNDING AND $0.00 IN NON-APPROPRIATED FUNDS; CUMULATIVE NA FUNDS - $431,254,316.85.' + }, + { + id: 40909, + type: 'D', + type_description: 'Unknown Type', + action_date: '11/7/2016', + action_type: 'C', + federal_action_obligation: '$21,007,166', + modification_number: '955', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $21,007,166.00 IN DOE APPROPRIATED FUNDING AND $0.00 IN NON-APPROPRIATED FUNDS; CUMULATIVE NA FUNDS - $431,254,316.85.' + }, + { + id: 40908, + type: 'D', + type_description: 'Unknown Type', + action_date: '11/8/2016', + action_type: 'B', + federal_action_obligation: '$0', + modification_number: '954', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - REVISE APPENDIX E TO INCORPORATE RCN OR-66' + }, + { + id: 39973, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/27/2016', + action_type: null, + federal_action_obligation: '$1,537,201', + modification_number: '953', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - TAS::97 0400::TAS - OBLIGATE SPP DOD FUNDING - OCTOBER 27 2016' + }, + { + id: 39849, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/27/2016', + action_type: null, + federal_action_obligation: '$25,840,226', + modification_number: '952', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $25,840,225.75 IN DOE APPROPRIATED FUNDING AND $0.00 IN NON-APPROPRIATED FUNDS; CUMULATIVE NA FUNDS - $431,254,316.85.' + }, + { + id: 39862, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/20/2016', + action_type: null, + federal_action_obligation: '$154,805,714', + modification_number: '951', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $154,805,714.00 IN DOE APPROPRIATED FUNDING AND $0.00 IN NON-APPROPRIATED FUNDS; CUMULATIVE NA FUNDS - $431,254,316.85.' + }, + { + id: 36839, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/26/2015', + action_type: null, + federal_action_obligation: '$498,104', + modification_number: '913', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - TAS::68 0108::TAS - OBLIGATE SPP EPA FUNDING - OCTOBER 2015' + }, + { + id: 36757, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/26/2015', + action_type: null, + federal_action_obligation: '$150,330,700', + modification_number: '912', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - OBLIGATE $150,330,700.26 IN DOE APPROPRIATED FUNDING; NON-APPROPRIATED FUNDS CURRENT ACTION = $1,523,053.45; NON-APPROPRIATED FUNDS CUMULATIVE SINCE MOD. 234 = $413,663,188.76.' + }, + { + id: 36791, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/15/2015', + action_type: null, + federal_action_obligation: '$0', + modification_number: '911', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - REVISE APPENDIX E TO INCORPORATE RCN OR-62' + }, + { + id: 34869, + type: 'D', + type_description: 'Definitive Contract', + action_date: '10/30/2014', + action_type: null, + federal_action_obligation: '-$14,274', + modification_number: '860', + description: 'MANAGEMENT AND OPERATION OF THE OAK RIDGE NATIONAL LABORATORY - RECOVERY TAS::89 0227::TAS - DEOBLIGATE SC ARRA FUNDING FROM PROJECT ENTITLED "NUCLEAR PHYSICS - NUCLEAR SCIENCE WORKFORCE"' + } +]; + diff --git a/tests/containers/search/filters/agencyFilter/AgencyListContainer-test.jsx b/tests/containers/search/filters/agencyFilter/AgencyListContainer-test.jsx index dd336d21fd..313cfac12a 100644 --- a/tests/containers/search/filters/agencyFilter/AgencyListContainer-test.jsx +++ b/tests/containers/search/filters/agencyFilter/AgencyListContainer-test.jsx @@ -9,9 +9,11 @@ import sinon from 'sinon'; import { OrderedMap } from 'immutable'; import { AgencyListContainer } from 'containers/search/filters/AgencyListContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import * as agencyActions from 'redux/actions/search/agencyActions'; +jest.mock('helpers/searchHelper', () => require('../searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + const setup = (props) => mount(); const initialFilters = { @@ -19,90 +21,6 @@ const initialFilters = { awardingAgencies: [] }; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - -const apiResponse = { - matched_objects: { - subtier_agency__name: [{ - id: 1788, - create_date: "2017-01-12T19:56:30.517000Z", - update_date: "2017-01-12T19:56:30.517000Z", - toptier_agency: { - toptier_agency_id: 268, - create_date: "2017-01-31T21:25:39.810344Z", - update_date: "2017-01-31T21:25:39.936439Z", - cgac_code: "097", - fpds_code: "9700", - name: "DEPT OF DEFENSE" - }, - subtier_agency: { - subtier_agency_id: 1654, - create_date: "2017-01-31T21:25:39.569918Z", - update_date: "2017-01-31T21:25:39.691244Z", - subtier_code: "1700", - name: "DEPT OF THE NAVY" - }, - office_agency: null - }, { - id: 1789, - create_date: "2017-01-12T19:56:30.522000Z", - update_date: "2017-01-12T19:56:30.522000Z", - toptier_agency: { - toptier_agency_id: 268, - create_date: "2017-01-31T21:25:39.810344Z", - update_date: "2017-01-31T21:25:39.936439Z", - cgac_code: "097", - fpds_code: "9700", - name: "DEPT OF DEFENSE" - }, - subtier_agency: { - subtier_agency_id: 1655, - create_date: "2017-01-31T21:25:39.569918Z", - update_date: "2017-01-31T21:25:39.691244Z", - subtier_code: "1708", - name: "IMMEDIATE OFFICE OF THE SECRETARY OF THE NAVY" - }, - office_agency: null - }] - } -}; - -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('AgencyListContainer', () => { describe('Handling text input', () => { it('should handle text input after 300ms', () => { @@ -162,9 +80,6 @@ describe('AgencyListContainer', () => { // Run fake timer for input delay jest.useFakeTimers().runTimersToTime(1000); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); - // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); expect(queryAutocompleteAgenciesSpy.callCount).toEqual(1); @@ -197,6 +112,8 @@ describe('AgencyListContainer', () => { value: 'N' } }; + + // Call handleTextInput function agencyListContainer.instance().handleTextInput(searchQuery); // Run fake timer for input delay @@ -237,13 +154,12 @@ describe('AgencyListContainer', () => { value: 'The Navy' } }; - agencyListContainer.instance().handleTextInput(searchQuery); - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(300); + // Call handleTextInput function + agencyListContainer.instance().handleTextInput(searchQuery); // Run fake timer for input delay - jest.runAllTicks(); + jest.useFakeTimers().runTimersToTime(1000); // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); @@ -254,7 +170,7 @@ describe('AgencyListContainer', () => { queryAutocompleteAgenciesSpy.reset(); }); - it('should populate Funding Agencies after performing the search', () => { + it('should populate Funding Agencies after performing the search', async () => { // Setup redux state const reduxState = [ { @@ -314,15 +230,6 @@ describe('AgencyListContainer', () => { selectedAgencies: new OrderedMap() }); - // Mock the search helper to resolve with the mocked response - mockSearchHelper('fetchAgencies', 'resolve', apiResponse); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(10000); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteAgenciesSpy = sinon.spy(agencyListContainer.instance(), 'queryAutocompleteAgencies'); @@ -330,17 +237,12 @@ describe('AgencyListContainer', () => { 'parseAutocompleteAgencies'); agencyListContainer.instance().queryAutocompleteAgencies('The Navy'); - - // Run all ticks - jest.runAllTicks(); + await agencyListContainer.instance().agencySearchRequest.promise; expect(queryAutocompleteAgenciesSpy.callCount).toEqual(1); expect(parseAutocompleteAgenciesSpy.calledWith(queryAutocompleteAgenciesSpy)); expect(mockReduxActionFunding).toHaveBeenCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteAgenciesSpy.reset(); parseAutocompleteAgenciesSpy.reset(); @@ -369,13 +271,12 @@ describe('AgencyListContainer', () => { value: 'The Navy' } }; - agencyListContainer.instance().handleTextInput(searchQuery); - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(300); + // Call handleTextInput function + agencyListContainer.instance().handleTextInput(searchQuery); // Run fake timer for input delay - jest.runAllTicks(); + jest.useFakeTimers().runTimersToTime(1000); // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); @@ -386,7 +287,7 @@ describe('AgencyListContainer', () => { queryAutocompleteAgenciesSpy.reset(); }); - it('should populate Awarding Agencies after performing the search', () => { + it('should populate Awarding Agencies after performing the search', async () => { // Setup redux state const reduxState = [ { @@ -446,12 +347,6 @@ describe('AgencyListContainer', () => { selectedAgencies: new OrderedMap() }); - // mock the search helper to resolve with the mocked response - mockSearchHelper('fetchAgencies', 'resolve', apiResponse); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteAgenciesSpy = sinon.spy(agencyListContainer.instance(), 'queryAutocompleteAgencies'); @@ -459,18 +354,13 @@ describe('AgencyListContainer', () => { 'parseAutocompleteAgencies'); agencyListContainer.instance().queryAutocompleteAgencies('The Navy'); - - // Run all ticks - jest.runAllTicks(); + await agencyListContainer.instance().agencySearchRequest.promise; // everything should be updated now expect(queryAutocompleteAgenciesSpy.callCount).toEqual(1); expect(parseAutocompleteAgenciesSpy.calledWith(queryAutocompleteAgenciesSpy)); expect(mockReduxActionAwarding).toHaveBeenCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteAgenciesSpy.reset(); parseAutocompleteAgenciesSpy.reset(); diff --git a/tests/containers/search/filters/agencyFilter/mockAgencies.js b/tests/containers/search/filters/agencyFilter/mockAgencies.js new file mode 100644 index 0000000000..2d90abc85c --- /dev/null +++ b/tests/containers/search/filters/agencyFilter/mockAgencies.js @@ -0,0 +1,45 @@ +export const mockAgencies = { + matched_objects: { + subtier_agency__name: [{ + id: 1788, + create_date: "2017-01-12T19:56:30.517000Z", + update_date: "2017-01-12T19:56:30.517000Z", + toptier_agency: { + toptier_agency_id: 268, + create_date: "2017-01-31T21:25:39.810344Z", + update_date: "2017-01-31T21:25:39.936439Z", + cgac_code: "097", + fpds_code: "9700", + name: "DEPT OF DEFENSE" + }, + subtier_agency: { + subtier_agency_id: 1654, + create_date: "2017-01-31T21:25:39.569918Z", + update_date: "2017-01-31T21:25:39.691244Z", + subtier_code: "1700", + name: "DEPT OF THE NAVY" + }, + office_agency: null + }, { + id: 1789, + create_date: "2017-01-12T19:56:30.522000Z", + update_date: "2017-01-12T19:56:30.522000Z", + toptier_agency: { + toptier_agency_id: 268, + create_date: "2017-01-31T21:25:39.810344Z", + update_date: "2017-01-31T21:25:39.936439Z", + cgac_code: "097", + fpds_code: "9700", + name: "DEPT OF DEFENSE" + }, + subtier_agency: { + subtier_agency_id: 1655, + create_date: "2017-01-31T21:25:39.569918Z", + update_date: "2017-01-31T21:25:39.691244Z", + subtier_code: "1708", + name: "IMMEDIATE OFFICE OF THE SECRETARY OF THE NAVY" + }, + office_agency: null + }] + } +}; diff --git a/tests/containers/search/filters/awardID/AwardIDListContainer-test.jsx b/tests/containers/search/filters/awardID/AwardIDListContainer-test.jsx index 7bd78709d4..81aa79c91c 100644 --- a/tests/containers/search/filters/awardID/AwardIDListContainer-test.jsx +++ b/tests/containers/search/filters/awardID/AwardIDListContainer-test.jsx @@ -9,9 +9,11 @@ import sinon from 'sinon'; import { OrderedMap } from 'immutable'; import { AwardIDListContainer } from 'containers/search/filters/awardID/AwardIDListContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import * as awardIDActions from 'redux/actions/search/awardIDActions'; +jest.mock('helpers/searchHelper', () => require('../searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + const setup = (props) => mount(); const initialFilters = { @@ -21,602 +23,14 @@ const initialFilters = { parent_award__piid: [] }; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - -const apiResponse = { - matched_objects: { - piid: [{ - id: "601793", - date_signed__fy: null, - data_source: null, - type: "U", - type_description: "Unknown Type", - piid: "AG3142B100012", - fain: null, - uri: null, - total_obligation: null, - total_outlay: null, - date_signed: null, - description: null, - period_of_performance_start_date: null, - period_of_performance_current_end_date: null, - potential_total_value_of_award: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-28T18:01:59.717954Z", - update_date: "2017-02-28T18:01:59.717969Z", - parent_award: null, - awarding_agency: { - id: 999, - create_date: "2017-01-12T19:56:26.723000Z", - update_date: "2017-01-12T19:56:26.723000Z", - toptier_agency: { - toptier_agency_id: 155, - create_date: null, - update_date: null, - cgac_code: "012", - fpds_code: "1200", - name: "AGRICULTURE, DEPARTMENT OF" - }, - subtier_agency: { - subtier_agency_id: 865, - create_date: null, - update_date: null, - subtier_code: "1205", - name: "USDA, OFFICE OF THE CHIEF FINANCIAL OFFICER" - }, - office_agency: null - }, - funding_agency: null, - recipient: null, - place_of_performance: null, - latest_submission: null - }], - fain: [{ - id: 7662, - date_signed__fy: 2016, - data_source: "USA", - type: "04", - type_description: "Project Grant", - piid: null, - fain: "EMW2011FO10044", - uri: null, - total_obligation: "-144.00", - total_outlay: null, - date_signed: "2015-10-23", - description: "ASSISTANCE TO FIREFIGHTERS GRANT", - period_of_performance_start_date: "2012-02-24", - period_of_performance_current_end_date: "2013-04-04", - potential_total_value_of_award: null, - last_modified_date: "2015-11-12", - certified_date: null, - create_date: "2017-02-28T01:11:39.376297Z", - update_date: "2017-02-28T01:11:39.376310Z", - parent_award: null, - awarding_agency: { - id: 1476, - create_date: "2017-01-12T19:56:28.960000Z", - update_date: "2017-01-12T19:56:28.960000Z", - toptier_agency: { - toptier_agency_id: 204, - create_date: null, - update_date: null, - cgac_code: "070", - fpds_code: "7000", - name: "HOMELAND SECURITY, DEPARTMENT OF" - }, - subtier_agency: { - subtier_agency_id: 1342, - create_date: null, - update_date: null, - subtier_code: "7022", - name: "FEDERAL EMERGENCY MANAGEMENT AGENCY" - }, - office_agency: null - }, - funding_agency: null, - recipient: { - legal_entity_id: 3702, - data_source: null, - parent_recipient_unique_id: null, - recipient_name: "SALEM FIRE & EMS DEPARTMENT", - vendor_doing_as_business_name: null, - vendor_phone_number: null, - vendor_fax_number: null, - business_types: "UN", - business_types_description: "Unknown Business Type", - recipient_unique_id: "931542034", - limited_liability_corporation: null, - sole_proprietorship: null, - partnership_or_limited_liability_partnership: null, - subchapter_scorporation: null, - foundation: null, - for_profit_organization: null, - nonprofit_organization: null, - corporate_entity_tax_exempt: null, - corporate_entity_not_tax_exempt: null, - other_not_for_profit_organization: null, - sam_exception: null, - city_local_government: null, - county_local_government: null, - inter_municipal_local_government: null, - local_government_owned: null, - municipality_local_government: null, - school_district_local_government: null, - township_local_government: null, - us_state_government: null, - us_federal_government: null, - federal_agency: null, - federally_funded_research_and_development_corp: null, - us_tribal_government: null, - foreign_government: null, - community_developed_corporation_owned_firm: null, - labor_surplus_area_firm: null, - small_agricultural_cooperative: null, - international_organization: null, - us_government_entity: null, - emerging_small_business: null, - c8a_program_participant: null, - sba_certified_8a_joint_venture: null, - dot_certified_disadvantage: null, - self_certified_small_disadvantaged_business: null, - historically_underutilized_business_zone: null, - small_disadvantaged_business: null, - the_ability_one_program: null, - historically_black_college: null, - c1862_land_grant_college: null, - c1890_land_grant_college: null, - c1994_land_grant_college: null, - minority_institution: null, - private_university_or_college: null, - school_of_forestry: null, - state_controlled_institution_of_higher_learning: null, - tribal_college: null, - veterinary_college: null, - educational_institution: null, - alaskan_native_servicing_institution: null, - community_development_corporation: null, - native_hawaiian_servicing_institution: null, - domestic_shelter: null, - manufacturer_of_goods: null, - hospital_flag: null, - veterinary_hospital: null, - hispanic_servicing_institution: null, - woman_owned_business: null, - minority_owned_business: null, - women_owned_small_business: null, - economically_disadvantaged_women_owned_small_business: null, - joint_venture_women_owned_small_business: null, - joint_venture_economic_disadvantaged_women_owned_small_bus: null, - veteran_owned_business: null, - service_disabled_veteran_owned_business: null, - contracts: null, - grants: null, - receives_contracts_and_grants: null, - airport_authority: null, - council_of_governments: null, - housing_authorities_public_tribal: null, - interstate_entity: null, - planning_commission: null, - port_authority: null, - transit_authority: null, - foreign_owned_and_located: null, - american_indian_owned_business: null, - alaskan_native_owned_corporation_or_firm: null, - indian_tribe_federally_recognized: null, - native_hawaiian_owned_business: null, - tribally_owned_business: null, - asian_pacific_american_owned_business: null, - black_american_owned_business: null, - hispanic_american_owned_business: null, - native_american_owned_business: null, - subcontinent_asian_asian_indian_american_owned_business: null, - other_minority_owned_business: null, - us_local_government: null, - undefinitized_action: null, - domestic_or_foreign_entity: null, - division_name: null, - division_number: null, - last_modified_date: null, - certified_date: null, - reporting_period_start: null, - reporting_period_end: null, - create_date: "2017-02-28T01:09:55.820873Z", - update_date: "2017-02-28T01:09:55.820887Z", - city_township_government: "Y", - special_district_government: null, - small_business: null, - individual: null, - location: { - location_id: 8106, - data_source: null, - country_name: "UNITED STATES", - state_code: "VA", - state_name: null, - state_description: null, - city_name: "SALEM", - city_code: "95547", - county_name: "SALEM (CITY)", - county_code: "775", - address_line1: "216 SOUTH BROAD STREET", - address_line2: "", - address_line3: "", - foreign_location_description: null, - zip4: null, - zip_4a: null, - congressional_code: null, - performance_code: null, - zip_last4: "3808", - zip5: "24153", - foreign_postal_code: null, - foreign_province: null, - foreign_city_name: null, - reporting_period_start: null, - reporting_period_end: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-28T01:09:55.816777Z", - update_date: "2017-02-28T01:09:55.816792Z", - place_of_performance_flag: false, - recipient_flag: false, - location_country_code: "USA" - } - }, - place_of_performance: { - location_id: 8105, - data_source: null, - country_name: "UNITED STATES", - state_code: "VA", - state_name: "VIRGINIA", - state_description: null, - city_name: null, - city_code: null, - county_name: "SALEM", - county_code: null, - address_line1: null, - address_line2: null, - address_line3: null, - foreign_location_description: null, - zip4: null, - zip_4a: null, - congressional_code: null, - performance_code: null, - zip_last4: "3808", - zip5: "24153", - foreign_postal_code: null, - foreign_province: null, - foreign_city_name: null, - reporting_period_start: null, - reporting_period_end: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-28T01:09:55.809970Z", - update_date: "2017-02-28T01:09:55.809986Z", - place_of_performance_flag: false, - recipient_flag: false, - location_country_code: "USA" - }, - latest_submission: 2 - }], - uri: [{ - id: 614186, - date_signed__fy: null, - data_source: null, - type: "U", - type_description: "Unknown Type", - piid: null, - fain: null, - uri: "8810075010:1", - total_obligation: null, - total_outlay: null, - date_signed: null, - description: null, - period_of_performance_start_date: null, - period_of_performance_current_end_date: null, - potential_total_value_of_award: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-03-03T20:55:46.622610Z", - update_date: "2017-03-03T20:55:46.905588Z", - parent_award: null, - awarding_agency: null, - funding_agency: null, - recipient: null, - place_of_performance: null, - latest_submission: 58 - }], - parent_award__piid: [{ - id: 423365, - date_signed__fy: 2016, - data_source: "USA", - type: "C", - type_description: "Delivery Order", - piid: "HHSF22301011T", - fain: null, - uri: null, - total_obligation: "-3662.72", - total_outlay: null, - date_signed: "2016-07-26", - description: "CENTER FOR TOBACCO (CTP) SHRED SERVICES", - period_of_performance_start_date: "2016-07-26", - period_of_performance_current_end_date: "2013-01-13", - potential_total_value_of_award: "-3662.72", - last_modified_date: "2016-07-28", - certified_date: null, - create_date: "2017-02-28T12:34:56.041258Z", - update_date: "2017-02-28T12:34:56.041272Z", - parent_award: 394555, - awarding_agency: { - id: 1508, - create_date: "2017-01-12T19:56:29.111000Z", - update_date: "2017-01-12T19:56:29.111000Z", - toptier_agency: { - toptier_agency_id: 209, - create_date: null, - update_date: null, - cgac_code: "075", - fpds_code: "7500", - name: "HEALTH AND HUMAN SERVICES, DEPARTMENT OF" - }, - subtier_agency: { - subtier_agency_id: 1374, - create_date: null, - update_date: null, - subtier_code: "7524", - name: "FOOD AND DRUG ADMINISTRATION" - }, - office_agency: null - }, - funding_agency: { - id: 1508, - create_date: "2017-01-12T19:56:29.111000Z", - update_date: "2017-01-12T19:56:29.111000Z", - toptier_agency: { - toptier_agency_id: 209, - create_date: null, - update_date: null, - cgac_code: "075", - fpds_code: "7500", - name: "HEALTH AND HUMAN SERVICES, DEPARTMENT OF" - }, - subtier_agency: { - subtier_agency_id: 1374, - create_date: null, - update_date: null, - subtier_code: "7524", - name: "FOOD AND DRUG ADMINISTRATION" - }, - office_agency: null - }, - recipient: { - legal_entity_id: 61210, - data_source: null, - parent_recipient_unique_id: "192398134", - recipient_name: "TRUSTED TECHNOLOGIES, LLC", - vendor_doing_as_business_name: null, - vendor_phone_number: "4103279221", - vendor_fax_number: "4436390055", - business_types: "UN", - business_types_description: "Unknown Business Type", - recipient_unique_id: "192398134", - limited_liability_corporation: "t", - sole_proprietorship: "f", - partnership_or_limited_liability_partnership: "f", - subchapter_scorporation: "f", - foundation: "f", - for_profit_organization: "t", - nonprofit_organization: "f", - corporate_entity_tax_exempt: "f", - corporate_entity_not_tax_exempt: "f", - other_not_for_profit_organization: "f", - sam_exception: null, - city_local_government: "f", - county_local_government: "f", - inter_municipal_local_government: "f", - local_government_owned: "f", - municipality_local_government: "f", - school_district_local_government: "f", - township_local_government: "f", - us_state_government: null, - us_federal_government: "f", - federal_agency: "f", - federally_funded_research_and_development_corp: "f", - us_tribal_government: "f", - foreign_government: "f", - community_developed_corporation_owned_firm: "f", - labor_surplus_area_firm: "f", - small_agricultural_cooperative: "f", - international_organization: "f", - us_government_entity: null, - emerging_small_business: null, - c8a_program_participant: "t", - sba_certified_8a_joint_venture: null, - dot_certified_disadvantage: "f", - self_certified_small_disadvantaged_business: null, - historically_underutilized_business_zone: "f", - small_disadvantaged_business: null, - the_ability_one_program: null, - historically_black_college: "f", - c1862_land_grant_college: "f", - c1890_land_grant_college: "f", - c1994_land_grant_college: "f", - minority_institution: "f", - private_university_or_college: "f", - school_of_forestry: "f", - state_controlled_institution_of_higher_learning: "f", - tribal_college: "f", - veterinary_college: "f", - educational_institution: "f", - alaskan_native_servicing_institution: "f", - community_development_corporation: "f", - native_hawaiian_servicing_institution: "f", - domestic_shelter: "f", - manufacturer_of_goods: "f", - hospital_flag: "f", - veterinary_hospital: "f", - hispanic_servicing_institution: "f", - woman_owned_business: "f", - minority_owned_business: "t", - women_owned_small_business: null, - economically_disadvantaged_women_owned_small_business: null, - joint_venture_women_owned_small_business: null, - joint_venture_economic_disadvantaged_women_owned_small_bus: null, - veteran_owned_business: "f", - service_disabled_veteran_owned_business: null, - contracts: null, - grants: null, - receives_contracts_and_grants: null, - airport_authority: "f", - council_of_governments: "f", - housing_authorities_public_tribal: "f", - interstate_entity: "f", - planning_commission: "f", - port_authority: "f", - transit_authority: "f", - foreign_owned_and_located: "f", - american_indian_owned_business: "f", - alaskan_native_owned_corporation_or_firm: "f", - indian_tribe_federally_recognized: "f", - native_hawaiian_owned_business: "f", - tribally_owned_business: "f", - asian_pacific_american_owned_business: "f", - black_american_owned_business: "t", - hispanic_american_owned_business: "f", - native_american_owned_business: "f", - subcontinent_asian_asian_indian_american_owned_business: "f", - other_minority_owned_business: "f", - us_local_government: "f", - undefinitized_action: null, - domestic_or_foreign_entity: null, - division_name: null, - division_number: null, - last_modified_date: null, - certified_date: null, - reporting_period_start: null, - reporting_period_end: null, - create_date: "2017-02-28T11:42:49.850471Z", - update_date: "2017-02-28T11:42:49.850483Z", - city_township_government: null, - special_district_government: null, - small_business: null, - individual: null, - location: { - location_id: 167302, - data_source: null, - country_name: "UNITED STATES", - state_code: "MD", - state_name: null, - state_description: null, - city_name: "BALTIMORE", - city_code: null, - county_name: null, - county_code: null, - address_line1: "2400 BOSTON ST STE 344", - address_line2: "", - address_line3: "", - foreign_location_description: null, - zip4: null, - zip_4a: null, - congressional_code: "03", - performance_code: null, - zip_last4: "4723", - zip5: "21224", - foreign_postal_code: null, - foreign_province: null, - foreign_city_name: null, - reporting_period_start: null, - reporting_period_end: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-28T11:42:49.846874Z", - update_date: "2017-02-28T11:42:49.846888Z", - place_of_performance_flag: false, - recipient_flag: false, - location_country_code: "USA" - } - }, - place_of_performance: { - location_id: 152383, - data_source: null, - country_name: "UNITED STATES", - state_code: "MD", - state_name: null, - state_description: null, - city_name: "ROCKVILLE", - city_code: null, - county_name: null, - county_code: null, - address_line1: null, - address_line2: null, - address_line3: null, - foreign_location_description: null, - zip4: null, - zip_4a: null, - congressional_code: "08", - performance_code: null, - zip_last4: "0003", - zip5: "20857", - foreign_postal_code: null, - foreign_province: null, - foreign_city_name: null, - reporting_period_start: null, - reporting_period_end: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-28T10:14:49.253099Z", - update_date: "2017-02-28T10:14:49.253112Z", - place_of_performance_flag: false, - recipient_flag: false, - location_country_code: "USA" - }, - latest_submission: 46 - }] - } -}; - -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('AwardIDListContainer', () => { describe('Handling text input', () => { it('should handle text input after 300ms', () => { // setup the award ID list container and call the function to type a single letter const awardIDListContainer = setup({ reduxFilters: initialFilters, - setAutocompleteAwardIDs: awardIDActions.setAutocompleteAwardIDs + setAutocompleteAwardIDs: awardIDActions.setAutocompleteAwardIDs, + toggleAwardID: jest.fn() }); const searchQuery = { @@ -648,7 +62,8 @@ describe('AwardIDListContainer', () => { // setup the award ID list container and call the function to type a single letter const awardIDListContainer = setup({ reduxFilters: initialFilters, - setAutocompleteAwardIDs: awardIDActions.setAutocompleteAwardIDs + setAutocompleteAwardIDs: awardIDActions.setAutocompleteAwardIDs, + toggleAwardID: jest.fn() }); const searchQuery = { @@ -687,7 +102,8 @@ describe('AwardIDListContainer', () => { // setup the award ID list container and call the function to type a single letter const awardIDListContainer = setup({ reduxFilters: initialFilters, - setAutocompleteAwardIDs: mockReduxAction + setAutocompleteAwardIDs: mockReduxAction, + toggleAwardID: jest.fn() }); const queryAutocompleteAwardIDsSpy = sinon.spy(awardIDListContainer.instance(), @@ -724,7 +140,8 @@ describe('AwardIDListContainer', () => { const awardIDListContainer = setup({ reduxFilters: initialFilters, setAutocompleteAwardIDs: mockReduxActionFunding, - selectedAwardIDs: new OrderedMap() + selectedAwardIDs: new OrderedMap(), + toggleAwardID: jest.fn() }); // set up spies @@ -755,7 +172,7 @@ describe('AwardIDListContainer', () => { queryAutocompleteAwardIDsSpy.reset(); }); - it('should populate Award IDs after performing the search', () => { + it('should populate Award IDs after performing the search', async () => { // Setup redux state const reduxState = [ { @@ -816,18 +233,10 @@ describe('AwardIDListContainer', () => { reduxFilters: initialFilters, setAutocompleteAwardIDs: mockReduxAction, piid: reduxState, - selectedAwardIDs: new OrderedMap() + selectedAwardIDs: new OrderedMap(), + toggleAwardID: jest.fn() }); - // Mock the search helper to resolve with the mocked response - mockSearchHelper('fetchAwardIDs', 'resolve', apiResponse); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(10000); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteAwardIDsSpy = sinon.spy(awardIDListContainer.instance(), 'queryAutocompleteAwardIDs'); @@ -836,16 +245,12 @@ describe('AwardIDListContainer', () => { awardIDListContainer.instance().queryAutocompleteAwardIDs('The Navy'); - // Run all ticks - jest.runAllTicks(); + await awardIDListContainer.instance().awardIDSearchRequest.promise; expect(queryAutocompleteAwardIDsSpy.callCount).toEqual(1); expect(parseAutocompleteAwardIDsSpy.calledWith(queryAutocompleteAwardIDsSpy)); expect(mockReduxAction).toHaveBeenCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteAwardIDsSpy.reset(); parseAutocompleteAwardIDsSpy.reset(); @@ -1408,7 +813,8 @@ describe('AwardIDListContainer', () => { }, latest_submission: 46 }], - selectedAwardIDs: new OrderedMap() + selectedAwardIDs: new OrderedMap(), + toggleAwardID: jest.fn() }); // Set up spies diff --git a/tests/containers/search/filters/awardID/mockAwardIDs.js b/tests/containers/search/filters/awardID/mockAwardIDs.js new file mode 100644 index 0000000000..c84af909dc --- /dev/null +++ b/tests/containers/search/filters/awardID/mockAwardIDs.js @@ -0,0 +1,550 @@ +export const mockAwardIDs = { + matched_objects: { + piid: [{ + id: "601793", + date_signed__fy: null, + data_source: null, + type: "U", + type_description: "Unknown Type", + piid: "AG3142B100012", + fain: null, + uri: null, + total_obligation: null, + total_outlay: null, + date_signed: null, + description: null, + period_of_performance_start_date: null, + period_of_performance_current_end_date: null, + potential_total_value_of_award: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-02-28T18:01:59.717954Z", + update_date: "2017-02-28T18:01:59.717969Z", + parent_award: null, + awarding_agency: { + id: 999, + create_date: "2017-01-12T19:56:26.723000Z", + update_date: "2017-01-12T19:56:26.723000Z", + toptier_agency: { + toptier_agency_id: 155, + create_date: null, + update_date: null, + cgac_code: "012", + fpds_code: "1200", + name: "AGRICULTURE, DEPARTMENT OF" + }, + subtier_agency: { + subtier_agency_id: 865, + create_date: null, + update_date: null, + subtier_code: "1205", + name: "USDA, OFFICE OF THE CHIEF FINANCIAL OFFICER" + }, + office_agency: null + }, + funding_agency: null, + recipient: null, + place_of_performance: null, + latest_submission: null + }], + fain: [{ + id: 7662, + date_signed__fy: 2016, + data_source: "USA", + type: "04", + type_description: "Project Grant", + piid: null, + fain: "EMW2011FO10044", + uri: null, + total_obligation: "-144.00", + total_outlay: null, + date_signed: "2015-10-23", + description: "ASSISTANCE TO FIREFIGHTERS GRANT", + period_of_performance_start_date: "2012-02-24", + period_of_performance_current_end_date: "2013-04-04", + potential_total_value_of_award: null, + last_modified_date: "2015-11-12", + certified_date: null, + create_date: "2017-02-28T01:11:39.376297Z", + update_date: "2017-02-28T01:11:39.376310Z", + parent_award: null, + awarding_agency: { + id: 1476, + create_date: "2017-01-12T19:56:28.960000Z", + update_date: "2017-01-12T19:56:28.960000Z", + toptier_agency: { + toptier_agency_id: 204, + create_date: null, + update_date: null, + cgac_code: "070", + fpds_code: "7000", + name: "HOMELAND SECURITY, DEPARTMENT OF" + }, + subtier_agency: { + subtier_agency_id: 1342, + create_date: null, + update_date: null, + subtier_code: "7022", + name: "FEDERAL EMERGENCY MANAGEMENT AGENCY" + }, + office_agency: null + }, + funding_agency: null, + recipient: { + legal_entity_id: 3702, + data_source: null, + parent_recipient_unique_id: null, + recipient_name: "SALEM FIRE & EMS DEPARTMENT", + vendor_doing_as_business_name: null, + vendor_phone_number: null, + vendor_fax_number: null, + business_types: "UN", + business_types_description: "Unknown Business Type", + recipient_unique_id: "931542034", + limited_liability_corporation: null, + sole_proprietorship: null, + partnership_or_limited_liability_partnership: null, + subchapter_scorporation: null, + foundation: null, + for_profit_organization: null, + nonprofit_organization: null, + corporate_entity_tax_exempt: null, + corporate_entity_not_tax_exempt: null, + other_not_for_profit_organization: null, + sam_exception: null, + city_local_government: null, + county_local_government: null, + inter_municipal_local_government: null, + local_government_owned: null, + municipality_local_government: null, + school_district_local_government: null, + township_local_government: null, + us_state_government: null, + us_federal_government: null, + federal_agency: null, + federally_funded_research_and_development_corp: null, + us_tribal_government: null, + foreign_government: null, + community_developed_corporation_owned_firm: null, + labor_surplus_area_firm: null, + small_agricultural_cooperative: null, + international_organization: null, + us_government_entity: null, + emerging_small_business: null, + c8a_program_participant: null, + sba_certified_8a_joint_venture: null, + dot_certified_disadvantage: null, + self_certified_small_disadvantaged_business: null, + historically_underutilized_business_zone: null, + small_disadvantaged_business: null, + the_ability_one_program: null, + historically_black_college: null, + c1862_land_grant_college: null, + c1890_land_grant_college: null, + c1994_land_grant_college: null, + minority_institution: null, + private_university_or_college: null, + school_of_forestry: null, + state_controlled_institution_of_higher_learning: null, + tribal_college: null, + veterinary_college: null, + educational_institution: null, + alaskan_native_servicing_institution: null, + community_development_corporation: null, + native_hawaiian_servicing_institution: null, + domestic_shelter: null, + manufacturer_of_goods: null, + hospital_flag: null, + veterinary_hospital: null, + hispanic_servicing_institution: null, + woman_owned_business: null, + minority_owned_business: null, + women_owned_small_business: null, + economically_disadvantaged_women_owned_small_business: null, + joint_venture_women_owned_small_business: null, + joint_venture_economic_disadvantaged_women_owned_small_bus: null, + veteran_owned_business: null, + service_disabled_veteran_owned_business: null, + contracts: null, + grants: null, + receives_contracts_and_grants: null, + airport_authority: null, + council_of_governments: null, + housing_authorities_public_tribal: null, + interstate_entity: null, + planning_commission: null, + port_authority: null, + transit_authority: null, + foreign_owned_and_located: null, + american_indian_owned_business: null, + alaskan_native_owned_corporation_or_firm: null, + indian_tribe_federally_recognized: null, + native_hawaiian_owned_business: null, + tribally_owned_business: null, + asian_pacific_american_owned_business: null, + black_american_owned_business: null, + hispanic_american_owned_business: null, + native_american_owned_business: null, + subcontinent_asian_asian_indian_american_owned_business: null, + other_minority_owned_business: null, + us_local_government: null, + undefinitized_action: null, + domestic_or_foreign_entity: null, + division_name: null, + division_number: null, + last_modified_date: null, + certified_date: null, + reporting_period_start: null, + reporting_period_end: null, + create_date: "2017-02-28T01:09:55.820873Z", + update_date: "2017-02-28T01:09:55.820887Z", + city_township_government: "Y", + special_district_government: null, + small_business: null, + individual: null, + location: { + location_id: 8106, + data_source: null, + country_name: "UNITED STATES", + state_code: "VA", + state_name: null, + state_description: null, + city_name: "SALEM", + city_code: "95547", + county_name: "SALEM (CITY)", + county_code: "775", + address_line1: "216 SOUTH BROAD STREET", + address_line2: "", + address_line3: "", + foreign_location_description: null, + zip4: null, + zip_4a: null, + congressional_code: null, + performance_code: null, + zip_last4: "3808", + zip5: "24153", + foreign_postal_code: null, + foreign_province: null, + foreign_city_name: null, + reporting_period_start: null, + reporting_period_end: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-02-28T01:09:55.816777Z", + update_date: "2017-02-28T01:09:55.816792Z", + place_of_performance_flag: false, + recipient_flag: false, + location_country_code: "USA" + } + }, + place_of_performance: { + location_id: 8105, + data_source: null, + country_name: "UNITED STATES", + state_code: "VA", + state_name: "VIRGINIA", + state_description: null, + city_name: null, + city_code: null, + county_name: "SALEM", + county_code: null, + address_line1: null, + address_line2: null, + address_line3: null, + foreign_location_description: null, + zip4: null, + zip_4a: null, + congressional_code: null, + performance_code: null, + zip_last4: "3808", + zip5: "24153", + foreign_postal_code: null, + foreign_province: null, + foreign_city_name: null, + reporting_period_start: null, + reporting_period_end: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-02-28T01:09:55.809970Z", + update_date: "2017-02-28T01:09:55.809986Z", + place_of_performance_flag: false, + recipient_flag: false, + location_country_code: "USA" + }, + latest_submission: 2 + }], + uri: [{ + id: 614186, + date_signed__fy: null, + data_source: null, + type: "U", + type_description: "Unknown Type", + piid: null, + fain: null, + uri: "8810075010:1", + total_obligation: null, + total_outlay: null, + date_signed: null, + description: null, + period_of_performance_start_date: null, + period_of_performance_current_end_date: null, + potential_total_value_of_award: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-03-03T20:55:46.622610Z", + update_date: "2017-03-03T20:55:46.905588Z", + parent_award: null, + awarding_agency: null, + funding_agency: null, + recipient: null, + place_of_performance: null, + latest_submission: 58 + }], + parent_award__piid: [{ + id: 423365, + date_signed__fy: 2016, + data_source: "USA", + type: "C", + type_description: "Delivery Order", + piid: "HHSF22301011T", + fain: null, + uri: null, + total_obligation: "-3662.72", + total_outlay: null, + date_signed: "2016-07-26", + description: "CENTER FOR TOBACCO (CTP) SHRED SERVICES", + period_of_performance_start_date: "2016-07-26", + period_of_performance_current_end_date: "2013-01-13", + potential_total_value_of_award: "-3662.72", + last_modified_date: "2016-07-28", + certified_date: null, + create_date: "2017-02-28T12:34:56.041258Z", + update_date: "2017-02-28T12:34:56.041272Z", + parent_award: 394555, + awarding_agency: { + id: 1508, + create_date: "2017-01-12T19:56:29.111000Z", + update_date: "2017-01-12T19:56:29.111000Z", + toptier_agency: { + toptier_agency_id: 209, + create_date: null, + update_date: null, + cgac_code: "075", + fpds_code: "7500", + name: "HEALTH AND HUMAN SERVICES, DEPARTMENT OF" + }, + subtier_agency: { + subtier_agency_id: 1374, + create_date: null, + update_date: null, + subtier_code: "7524", + name: "FOOD AND DRUG ADMINISTRATION" + }, + office_agency: null + }, + funding_agency: { + id: 1508, + create_date: "2017-01-12T19:56:29.111000Z", + update_date: "2017-01-12T19:56:29.111000Z", + toptier_agency: { + toptier_agency_id: 209, + create_date: null, + update_date: null, + cgac_code: "075", + fpds_code: "7500", + name: "HEALTH AND HUMAN SERVICES, DEPARTMENT OF" + }, + subtier_agency: { + subtier_agency_id: 1374, + create_date: null, + update_date: null, + subtier_code: "7524", + name: "FOOD AND DRUG ADMINISTRATION" + }, + office_agency: null + }, + recipient: { + legal_entity_id: 61210, + data_source: null, + parent_recipient_unique_id: "192398134", + recipient_name: "TRUSTED TECHNOLOGIES, LLC", + vendor_doing_as_business_name: null, + vendor_phone_number: "4103279221", + vendor_fax_number: "4436390055", + business_types: "UN", + business_types_description: "Unknown Business Type", + recipient_unique_id: "192398134", + limited_liability_corporation: "t", + sole_proprietorship: "f", + partnership_or_limited_liability_partnership: "f", + subchapter_scorporation: "f", + foundation: "f", + for_profit_organization: "t", + nonprofit_organization: "f", + corporate_entity_tax_exempt: "f", + corporate_entity_not_tax_exempt: "f", + other_not_for_profit_organization: "f", + sam_exception: null, + city_local_government: "f", + county_local_government: "f", + inter_municipal_local_government: "f", + local_government_owned: "f", + municipality_local_government: "f", + school_district_local_government: "f", + township_local_government: "f", + us_state_government: null, + us_federal_government: "f", + federal_agency: "f", + federally_funded_research_and_development_corp: "f", + us_tribal_government: "f", + foreign_government: "f", + community_developed_corporation_owned_firm: "f", + labor_surplus_area_firm: "f", + small_agricultural_cooperative: "f", + international_organization: "f", + us_government_entity: null, + emerging_small_business: null, + c8a_program_participant: "t", + sba_certified_8a_joint_venture: null, + dot_certified_disadvantage: "f", + self_certified_small_disadvantaged_business: null, + historically_underutilized_business_zone: "f", + small_disadvantaged_business: null, + the_ability_one_program: null, + historically_black_college: "f", + c1862_land_grant_college: "f", + c1890_land_grant_college: "f", + c1994_land_grant_college: "f", + minority_institution: "f", + private_university_or_college: "f", + school_of_forestry: "f", + state_controlled_institution_of_higher_learning: "f", + tribal_college: "f", + veterinary_college: "f", + educational_institution: "f", + alaskan_native_servicing_institution: "f", + community_development_corporation: "f", + native_hawaiian_servicing_institution: "f", + domestic_shelter: "f", + manufacturer_of_goods: "f", + hospital_flag: "f", + veterinary_hospital: "f", + hispanic_servicing_institution: "f", + woman_owned_business: "f", + minority_owned_business: "t", + women_owned_small_business: null, + economically_disadvantaged_women_owned_small_business: null, + joint_venture_women_owned_small_business: null, + joint_venture_economic_disadvantaged_women_owned_small_bus: null, + veteran_owned_business: "f", + service_disabled_veteran_owned_business: null, + contracts: null, + grants: null, + receives_contracts_and_grants: null, + airport_authority: "f", + council_of_governments: "f", + housing_authorities_public_tribal: "f", + interstate_entity: "f", + planning_commission: "f", + port_authority: "f", + transit_authority: "f", + foreign_owned_and_located: "f", + american_indian_owned_business: "f", + alaskan_native_owned_corporation_or_firm: "f", + indian_tribe_federally_recognized: "f", + native_hawaiian_owned_business: "f", + tribally_owned_business: "f", + asian_pacific_american_owned_business: "f", + black_american_owned_business: "t", + hispanic_american_owned_business: "f", + native_american_owned_business: "f", + subcontinent_asian_asian_indian_american_owned_business: "f", + other_minority_owned_business: "f", + us_local_government: "f", + undefinitized_action: null, + domestic_or_foreign_entity: null, + division_name: null, + division_number: null, + last_modified_date: null, + certified_date: null, + reporting_period_start: null, + reporting_period_end: null, + create_date: "2017-02-28T11:42:49.850471Z", + update_date: "2017-02-28T11:42:49.850483Z", + city_township_government: null, + special_district_government: null, + small_business: null, + individual: null, + location: { + location_id: 167302, + data_source: null, + country_name: "UNITED STATES", + state_code: "MD", + state_name: null, + state_description: null, + city_name: "BALTIMORE", + city_code: null, + county_name: null, + county_code: null, + address_line1: "2400 BOSTON ST STE 344", + address_line2: "", + address_line3: "", + foreign_location_description: null, + zip4: null, + zip_4a: null, + congressional_code: "03", + performance_code: null, + zip_last4: "4723", + zip5: "21224", + foreign_postal_code: null, + foreign_province: null, + foreign_city_name: null, + reporting_period_start: null, + reporting_period_end: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-02-28T11:42:49.846874Z", + update_date: "2017-02-28T11:42:49.846888Z", + place_of_performance_flag: false, + recipient_flag: false, + location_country_code: "USA" + } + }, + place_of_performance: { + location_id: 152383, + data_source: null, + country_name: "UNITED STATES", + state_code: "MD", + state_name: null, + state_description: null, + city_name: "ROCKVILLE", + city_code: null, + county_name: null, + county_code: null, + address_line1: null, + address_line2: null, + address_line3: null, + foreign_location_description: null, + zip4: null, + zip_4a: null, + congressional_code: "08", + performance_code: null, + zip_last4: "0003", + zip5: "20857", + foreign_postal_code: null, + foreign_province: null, + foreign_city_name: null, + reporting_period_start: null, + reporting_period_end: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-02-28T10:14:49.253099Z", + update_date: "2017-02-28T10:14:49.253112Z", + place_of_performance_flag: false, + recipient_flag: false, + location_country_code: "USA" + }, + latest_submission: 46 + }] + } +}; diff --git a/tests/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer-test.jsx b/tests/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer-test.jsx index f373dd12b4..fda929046b 100644 --- a/tests/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer-test.jsx +++ b/tests/containers/search/filters/budgetCategory/BudgetCategoryAccountContainer-test.jsx @@ -11,67 +11,17 @@ import { OrderedMap } from 'immutable'; import { BudgetCategoryAccountContainer } from 'containers/search/filters/budgetCategory/BudgetCategoryAccountContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import * as budgetCategoryActions from 'redux/actions/search/budgetCategoryActions'; +jest.mock('helpers/searchHelper', () => require('../searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + const setup = (props) => mount(); const initialFilters = { autocompleteFederalAccounts: [] }; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - -const apiResponse = { - matched_objects: { - federal_account_code: { - account_title: "Special Supplemental Nutrition Program for Women, Infants and " + - "Children (WIC), Food and Nutrition Service", - agency_identifier: "012", - id: 391, - main_account_code: "3510", - federal_account_code: "012-3510 - Special Supplemental Nutrition Program for Women," + - "Infants and Children (WIC), Food and Nutrition Service" - } - } -}; - -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('BudgetCategoryAccountContainer', () => { describe('Handling text input', () => { it('should handle text input after 300ms', () => { @@ -81,7 +31,8 @@ describe('BudgetCategoryAccountContainer', () => { setAutocompleteFederalAccounts: budgetCategoryActions.setAutocompleteFederalAccounts, federalAccounts: new OrderedMap(), - autocompleteFederalAccounts: [] + autocompleteFederalAccounts: [], + updateFederalAccounts: jest.fn() }); const searchQuery = { @@ -117,7 +68,8 @@ describe('BudgetCategoryAccountContainer', () => { setAutocompleteFederalAccounts: budgetCategoryActions.setAutocompleteFederalAccounts, federalAccounts: new OrderedMap(), - autocompleteFederalAccounts: [] + autocompleteFederalAccounts: [], + updateFederalAccounts: jest.fn() }); const searchQuery = { @@ -159,7 +111,8 @@ describe('BudgetCategoryAccountContainer', () => { reduxFilters: initialFilters, setAutocompleteFederalAccounts: mockReduxAction, federalAccounts: new OrderedMap(), - autocompleteFederalAccounts: [] + autocompleteFederalAccounts: [], + updateFederalAccounts: jest.fn() }); const queryAutocompleteFederalAccountsSpy = sinon @@ -198,7 +151,8 @@ describe('BudgetCategoryAccountContainer', () => { reduxFilters: initialFilters, setAutocompleteFederalAccounts: mockReduxAction, federalAccounts: new OrderedMap(), - autocompleteFederalAccounts: [] + autocompleteFederalAccounts: [], + updateFederalAccounts: jest.fn() }); // set up spies @@ -229,7 +183,7 @@ describe('BudgetCategoryAccountContainer', () => { queryAutocompleteFederalAccountsSpy.reset(); }); - it('should populate Federal Accounts after performing the search', () => { + it('should populate Federal Accounts after performing the search', async () => { // Setup redux state const reduxState = [{ 391: { @@ -255,15 +209,6 @@ describe('BudgetCategoryAccountContainer', () => { updateFederalAccounts: jest.fn() }); - // Mock the search helper to resolve with the mocked response - mockSearchHelper('fetchFederalAccounts', 'resolve', apiResponse); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(10000); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteFederalAccountsSpy = sinon.spy( budgetCategoryAccountContainer.instance(), 'queryAutocompleteFederalAccounts'); @@ -272,18 +217,13 @@ describe('BudgetCategoryAccountContainer', () => { budgetCategoryAccountContainer.instance() .queryAutocompleteFederalAccounts('Income'); - - // Run all ticks - jest.runAllTicks(); + await budgetCategoryAccountContainer.instance().searchRequest.promise; expect(queryAutocompleteFederalAccountsSpy.callCount).toEqual(1); expect(parseAutocompleteFederalAccountsSpy .calledWith(queryAutocompleteFederalAccountsSpy)); expect(mockReduxAction).toHaveBeenCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteFederalAccountsSpy.reset(); parseAutocompleteFederalAccountsSpy.reset(); diff --git a/tests/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer-test.jsx b/tests/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer-test.jsx index 5f49533412..b0e934713e 100644 --- a/tests/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer-test.jsx +++ b/tests/containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer-test.jsx @@ -11,60 +11,17 @@ import { OrderedMap } from 'immutable'; import { BudgetCategoryFunctionContainer } from 'containers/search/filters/budgetCategory/BudgetCategoryFunctionContainer'; -import * as SearchHelper from 'helpers/searchHelper'; import * as budgetCategoryActions from 'redux/actions/search/budgetCategoryActions'; +jest.mock('helpers/searchHelper', () => require('../searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + const setup = (props) => mount(); const initialFilters = { autocompleteBudgetFunctions: [] }; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - -const apiResponse = { - results: { - budget_function_title: ['Income Security'], - budget_subfunction_title: ['Farm income stabilization'] - } -}; - -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('BudgetCategoryFunctionContainer', () => { describe('Handling text input', () => { it('should handle text input after 300ms', () => { @@ -74,7 +31,8 @@ describe('BudgetCategoryFunctionContainer', () => { setAutocompleteBudgetFunctions: budgetCategoryActions.setAutocompleteBudgetFunctions, budgetFunctions: new OrderedMap(), - autocompleteBudgetFunctions: [] + autocompleteBudgetFunctions: [], + updateBudgetFunctions: jest.fn() }); const searchQuery = { @@ -110,7 +68,8 @@ describe('BudgetCategoryFunctionContainer', () => { setAutocompleteBudgetFunctions: budgetCategoryActions.setAutocompleteBudgetFunctions, budgetFunctions: new OrderedMap(), - autocompleteBudgetFunctions: [] + autocompleteBudgetFunctions: [], + updateBudgetFunctions: jest.fn() }); const searchQuery = { @@ -152,7 +111,8 @@ describe('BudgetCategoryFunctionContainer', () => { reduxFilters: initialFilters, setAutocompleteBudgetFunctions: mockReduxAction, budgetFunctions: new OrderedMap(), - autocompleteBudgetFunctions: [] + autocompleteBudgetFunctions: [], + updateBudgetFunctions: jest.fn() }); const queryAutocompleteBudgetFunctionsSpy = sinon @@ -191,7 +151,8 @@ describe('BudgetCategoryFunctionContainer', () => { reduxFilters: initialFilters, setAutocompleteBudgetFunctions: mockReduxAction, budgetFunctions: new OrderedMap(), - autocompleteBudgetFunctions: [] + autocompleteBudgetFunctions: [], + updateBudgetFunctions: jest.fn() }); // set up spies @@ -222,7 +183,7 @@ describe('BudgetCategoryFunctionContainer', () => { queryAutocompleteBudgetFunctionsSpy.reset(); }); - it('should populate Budget Functions after performing the search', () => { + it('should populate Budget Functions after performing the search', async () => { // Setup redux state const reduxState = [{ 'Income Security': { @@ -245,15 +206,6 @@ describe('BudgetCategoryFunctionContainer', () => { updateBudgetFunctions: jest.fn() }); - // Mock the search helper to resolve with the mocked response - mockSearchHelper('fetchBudgetFunctions', 'resolve', apiResponse); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(10000); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteBudgetFunctionsSpy = sinon.spy( budgetCategoryFunctionContainer.instance(), 'queryAutocompleteBudgetFunctions'); @@ -263,17 +215,13 @@ describe('BudgetCategoryFunctionContainer', () => { budgetCategoryFunctionContainer.instance() .queryAutocompleteBudgetFunctions('Income'); - // Run all ticks - jest.runAllTicks(); + await budgetCategoryFunctionContainer.instance().searchRequest.promise; expect(queryAutocompleteBudgetFunctionsSpy.callCount).toEqual(1); expect(parseAutocompleteBudgetFunctionsSpy .calledWith(queryAutocompleteBudgetFunctionsSpy)); expect(mockReduxAction).toHaveBeenCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteBudgetFunctionsSpy.reset(); parseAutocompleteBudgetFunctionsSpy.reset(); diff --git a/tests/containers/search/filters/budgetCategory/mockBudgetCategories.js b/tests/containers/search/filters/budgetCategory/mockBudgetCategories.js new file mode 100644 index 0000000000..72033b8ce2 --- /dev/null +++ b/tests/containers/search/filters/budgetCategory/mockBudgetCategories.js @@ -0,0 +1,20 @@ +export const mockBudgetCategoryAccounts = { + matched_objects: { + federal_account_code: { + account_title: "Special Supplemental Nutrition Program for Women, Infants and " + + "Children (WIC), Food and Nutrition Service", + agency_identifier: "012", + id: 391, + main_account_code: "3510", + federal_account_code: "012-3510 - Special Supplemental Nutrition Program for Women," + + "Infants and Children (WIC), Food and Nutrition Service" + } + } +}; + +export const mockBudgetCategoryFunctions = { + results: { + budget_function_title: ['Income Security'], + budget_subfunction_title: ['Farm income stabilization'] + } +}; diff --git a/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx b/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx index 132568d2e9..2e31cb403c 100644 --- a/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx +++ b/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx @@ -20,196 +20,8 @@ const initialFilters = { autocompleteRecipients: [] }; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - -const apiResponse = { - matched_objects: { - recipient_name: { - legal_entity_id: 973, - data_source: null, - parent_recipient_unique_id: "964725688", - recipient_name: "BOOZ ALLEN HAMILTON INC.", - vendor_doing_as_business_name: null, - vendor_phone_number: "7033770195", - vendor_fax_number: "7039023200", - business_types: "UN", - business_types_description: "Unknown Business Type", - recipient_unique_id: "006928857", - limited_liability_corporation: "f", - sole_proprietorship: "f", - partnership_or_limited_liability_partnership: "f", - subchapter_scorporation: "f", - foundation: "f", - for_profit_organization: "t", - nonprofit_organization: "f", - corporate_entity_tax_exempt: "f", - corporate_entity_not_tax_exempt: "t", - other_not_for_profit_organization: "f", - sam_exception: null, - city_local_government: "f", - county_local_government: "f", - inter_municipal_local_government: "f", - local_government_owned: "f", - municipality_local_government: "f", - school_district_local_government: "f", - township_local_government: "f", - us_state_government: null, - us_federal_government: "f", - federal_agency: "f", - federally_funded_research_and_development_corp: "f", - us_tribal_government: "f", - foreign_government: "f", - community_developed_corporation_owned_firm: "f", - labor_surplus_area_firm: "f", - small_agricultural_cooperative: "f", - international_organization: "f", - us_government_entity: null, - emerging_small_business: null, - c8a_program_participant: "f", - sba_certified_8a_joint_venture: null, - dot_certified_disadvantage: "f", - self_certified_small_disadvantaged_business: null, - historically_underutilized_business_zone: "f", - small_disadvantaged_business: null, - the_ability_one_program: null, - historically_black_college: "f", - c1862_land_grant_college: "f", - c1890_land_grant_college: "f", - c1994_land_grant_college: "f", - minority_institution: "f", - private_university_or_college: "f", - school_of_forestry: "f", - state_controlled_institution_of_higher_learning: "f", - tribal_college: "f", - veterinary_college: "f", - educational_institution: "f", - alaskan_native_servicing_institution: "f", - community_development_corporation: "f", - native_hawaiian_servicing_institution: "f", - domestic_shelter: "f", - manufacturer_of_goods: "f", - hospital_flag: "f", - veterinary_hospital: "f", - hispanic_servicing_institution: "f", - woman_owned_business: "f", - minority_owned_business: "f", - women_owned_small_business: null, - economically_disadvantaged_women_owned_small_business: null, - joint_venture_women_owned_small_business: null, - joint_venture_economic_disadvantaged_women_owned_small_bus: null, - veteran_owned_business: "f", - service_disabled_veteran_owned_business: null, - contracts: null, - grants: null, - receives_contracts_and_grants: null, - airport_authority: "f", - council_of_governments: "f", - housing_authorities_public_tribal: "f", - interstate_entity: "f", - planning_commission: "f", - port_authority: "f", - transit_authority: "f", - foreign_owned_and_located: "f", - american_indian_owned_business: "f", - alaskan_native_owned_corporation_or_firm: "f", - indian_tribe_federally_recognized: "f", - native_hawaiian_owned_business: "f", - tribally_owned_business: "f", - asian_pacific_american_owned_business: "f", - black_american_owned_business: "f", - hispanic_american_owned_business: "f", - native_american_owned_business: "f", - subcontinent_asian_asian_indian_american_owned_business: "f", - other_minority_owned_business: "f", - us_local_government: "f", - undefinitized_action: null, - domestic_or_foreign_entity: null, - division_name: null, - division_number: null, - last_modified_date: null, - certified_date: null, - reporting_period_start: null, - reporting_period_end: null, - create_date: "2017-02-15T20:06:43.024083Z", - update_date: "2017-02-15T20:06:43.024108Z", - city_township_government: null, - special_district_government: null, - small_business: null, - individual: null, - location: { - location_id: 12619, - data_source: null, - country_name: "UNITED STATES", - state_code: "VA", - state_name: null, - state_description: null, - city_name: "McLean", - city_code: "48376", - county_name: "Fairfax", - county_code: "59", - address_line1: "8283 GREENSBORO DR", - address_line2: "", - address_line3: "", - foreign_location_description: null, - zip4: null, - zip_4a: null, - congressional_code: "11", - performance_code: null, - zip_last4: "3830", - zip5: "22102", - foreign_postal_code: null, - foreign_province: null, - foreign_city_name: null, - reporting_period_start: null, - reporting_period_end: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-15T20:32:31.411437Z", - update_date: "2017-02-15T20:32:31.411470Z", - place_of_performance_flag: false, - recipient_flag: false, - location_country_code: "USA" - } - }, - recipient_unique_id: [] - } -}; - -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; +jest.mock('helpers/searchHelper', () => require('../searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; describe('RecipientNameDUNSContainer', () => { describe('Handling text input', () => { @@ -363,7 +175,7 @@ describe('RecipientNameDUNSContainer', () => { queryAutocompleteRecipientsSpy.reset(); }); - it('should populate Recipients after performing the search', () => { + it('should populate Recipients after performing the search', async () => { // Setup redux state const reduxState = [{ legal_entity_id: 973, @@ -526,15 +338,6 @@ describe('RecipientNameDUNSContainer', () => { selectedRecipients: new OrderedMap() }); - // Mock the search helper to resolve with the mocked response - mockSearchHelper('fetchRecipients', 'resolve', apiResponse); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(10000); - - // Run all ticks - jest.runAllTicks(); - // Set up spies const queryAutocompleteRecipientsSpy = sinon.spy(recipientNameDUNSContainer.instance(), 'queryAutocompleteRecipients'); @@ -542,17 +345,13 @@ describe('RecipientNameDUNSContainer', () => { 'parseAutocompleteRecipients'); recipientNameDUNSContainer.instance().queryAutocompleteRecipients('Booz Allen'); + await recipientNameDUNSContainer.instance().recipientSearchRequest.promise; - // Run all ticks - jest.runAllTicks(); expect(queryAutocompleteRecipientsSpy.callCount).toEqual(1); expect(parseAutocompleteRecipientsSpy.calledWith(queryAutocompleteRecipientsSpy)); expect(mockReduxAction).toHaveBeenCalled(); - // Reset the mock - unmockSearchHelper(); - // Reset spies queryAutocompleteRecipientsSpy.reset(); parseAutocompleteRecipientsSpy.reset(); diff --git a/tests/containers/search/filters/recipientFilter/mockRecipients.js b/tests/containers/search/filters/recipientFilter/mockRecipients.js new file mode 100644 index 0000000000..2c0a63fd32 --- /dev/null +++ b/tests/containers/search/filters/recipientFilter/mockRecipients.js @@ -0,0 +1,159 @@ +export const mockRecipientLocation = [{ + place_type: "CITY", + matched_ids: [22516, 23056], + place: "MCLEAN", + parent: null +}]; + +export const mockRecipientDUNS = { + matched_objects: { + recipient_name: { + legal_entity_id: 973, + data_source: null, + parent_recipient_unique_id: "964725688", + recipient_name: "BOOZ ALLEN HAMILTON INC.", + vendor_doing_as_business_name: null, + vendor_phone_number: "7033770195", + vendor_fax_number: "7039023200", + business_types: "UN", + business_types_description: "Unknown Business Type", + recipient_unique_id: "006928857", + limited_liability_corporation: "f", + sole_proprietorship: "f", + partnership_or_limited_liability_partnership: "f", + subchapter_scorporation: "f", + foundation: "f", + for_profit_organization: "t", + nonprofit_organization: "f", + corporate_entity_tax_exempt: "f", + corporate_entity_not_tax_exempt: "t", + other_not_for_profit_organization: "f", + sam_exception: null, + city_local_government: "f", + county_local_government: "f", + inter_municipal_local_government: "f", + local_government_owned: "f", + municipality_local_government: "f", + school_district_local_government: "f", + township_local_government: "f", + us_state_government: null, + us_federal_government: "f", + federal_agency: "f", + federally_funded_research_and_development_corp: "f", + us_tribal_government: "f", + foreign_government: "f", + community_developed_corporation_owned_firm: "f", + labor_surplus_area_firm: "f", + small_agricultural_cooperative: "f", + international_organization: "f", + us_government_entity: null, + emerging_small_business: null, + c8a_program_participant: "f", + sba_certified_8a_joint_venture: null, + dot_certified_disadvantage: "f", + self_certified_small_disadvantaged_business: null, + historically_underutilized_business_zone: "f", + small_disadvantaged_business: null, + the_ability_one_program: null, + historically_black_college: "f", + c1862_land_grant_college: "f", + c1890_land_grant_college: "f", + c1994_land_grant_college: "f", + minority_institution: "f", + private_university_or_college: "f", + school_of_forestry: "f", + state_controlled_institution_of_higher_learning: "f", + tribal_college: "f", + veterinary_college: "f", + educational_institution: "f", + alaskan_native_servicing_institution: "f", + community_development_corporation: "f", + native_hawaiian_servicing_institution: "f", + domestic_shelter: "f", + manufacturer_of_goods: "f", + hospital_flag: "f", + veterinary_hospital: "f", + hispanic_servicing_institution: "f", + woman_owned_business: "f", + minority_owned_business: "f", + women_owned_small_business: null, + economically_disadvantaged_women_owned_small_business: null, + joint_venture_women_owned_small_business: null, + joint_venture_economic_disadvantaged_women_owned_small_bus: null, + veteran_owned_business: "f", + service_disabled_veteran_owned_business: null, + contracts: null, + grants: null, + receives_contracts_and_grants: null, + airport_authority: "f", + council_of_governments: "f", + housing_authorities_public_tribal: "f", + interstate_entity: "f", + planning_commission: "f", + port_authority: "f", + transit_authority: "f", + foreign_owned_and_located: "f", + american_indian_owned_business: "f", + alaskan_native_owned_corporation_or_firm: "f", + indian_tribe_federally_recognized: "f", + native_hawaiian_owned_business: "f", + tribally_owned_business: "f", + asian_pacific_american_owned_business: "f", + black_american_owned_business: "f", + hispanic_american_owned_business: "f", + native_american_owned_business: "f", + subcontinent_asian_asian_indian_american_owned_business: "f", + other_minority_owned_business: "f", + us_local_government: "f", + undefinitized_action: null, + domestic_or_foreign_entity: null, + division_name: null, + division_number: null, + last_modified_date: null, + certified_date: null, + reporting_period_start: null, + reporting_period_end: null, + create_date: "2017-02-15T20:06:43.024083Z", + update_date: "2017-02-15T20:06:43.024108Z", + city_township_government: null, + special_district_government: null, + small_business: null, + individual: null, + location: { + location_id: 12619, + data_source: null, + country_name: "UNITED STATES", + state_code: "VA", + state_name: null, + state_description: null, + city_name: "McLean", + city_code: "48376", + county_name: "Fairfax", + county_code: "59", + address_line1: "8283 GREENSBORO DR", + address_line2: "", + address_line3: "", + foreign_location_description: null, + zip4: null, + zip_4a: null, + congressional_code: "11", + performance_code: null, + zip_last4: "3830", + zip5: "22102", + foreign_postal_code: null, + foreign_province: null, + foreign_city_name: null, + reporting_period_start: null, + reporting_period_end: null, + last_modified_date: null, + certified_date: null, + create_date: "2017-02-15T20:32:31.411437Z", + update_date: "2017-02-15T20:32:31.411470Z", + place_of_performance_flag: false, + recipient_flag: false, + location_country_code: "USA" + } + }, + recipient_unique_id: [] + } +}; diff --git a/tests/containers/search/filters/searchHelper.js b/tests/containers/search/filters/searchHelper.js index 1ffb122cee..654dcc8479 100644 --- a/tests/containers/search/filters/searchHelper.js +++ b/tests/containers/search/filters/searchHelper.js @@ -1,8 +1,9 @@ -import { mockLocationAutocomplete } from '../../../redux/reducers/search/mock/mockRecipient'; -import { mockAwardResponse } from '../../../redux/reducers/award/mockAward'; -import { accountProgramActivities } - from '../../../redux/reducers/account/mockAccountProgramActivities'; - +import { mockRecipientLocation, mockRecipientDUNS } from './recipientFilter/mockRecipients'; +import { mockAgencies } from './agencyFilter/mockAgencies'; +import { mockAwardIDs } from './awardID/mockAwardIDs'; +import { mockBudgetCategoryAccounts, mockBudgetCategoryFunctions } + from './budgetCategory/mockBudgetCategories'; +import { mockApi, mockTabCount } from '../table/mockAwards'; // Fetch Locations for Autocomplete export const fetchLocations = () => ( @@ -10,7 +11,7 @@ export const fetchLocations = () => ( promise: new Promise((resolve) => { process.nextTick(() => { resolve({ - data: mockLocationAutocomplete + data: mockRecipientLocation }); }); }), @@ -18,13 +19,13 @@ export const fetchLocations = () => ( } ); -// Fetch Individual Awards -export const fetchAward = () => ( +// Fetch Recipients +export const fetchRecipients = () => ( { promise: new Promise((resolve) => { process.nextTick(() => { resolve({ - data: mockAwardResponse + data: mockRecipientDUNS }); }); }), @@ -32,16 +33,86 @@ export const fetchAward = () => ( } ); -// Fetch Program Activities -export const fetchProgramActivities = () => ( +// Fetch Agencies +export const fetchAgencies = () => ( { promise: new Promise((resolve) => { process.nextTick(() => { resolve({ - data: accountProgramActivities + data: mockAgencies }); }); }), cancel: jest.fn() } -); \ No newline at end of file +); + +// Fetch Award IDs +export const fetchAwardIDs = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockAwardIDs + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Federal Accounts +export const fetchFederalAccounts = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockBudgetCategoryAccounts + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Budget Functions +export const fetchBudgetFunctions = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockBudgetCategoryFunctions + }); + }); + }), + cancel: jest.fn() + } +); + +// Fetch Award Counts +export const fetchAwardCounts = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockTabCount + }); + }); + }), + cancel: jest.fn() + } +); + +// Perform Paged Search +export const performPagedSearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockApi + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/search/table/ResultsTableContainer-test.jsx b/tests/containers/search/table/ResultsTableContainer-test.jsx index 92541510dc..bc5ba36bcb 100644 --- a/tests/containers/search/table/ResultsTableContainer-test.jsx +++ b/tests/containers/search/table/ResultsTableContainer-test.jsx @@ -7,7 +7,6 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; -import * as SearchHelper from 'helpers/searchHelper'; import { ResultsTableContainer } from 'containers/search/table/ResultsTableContainer'; import { MetaRecord } from 'redux/reducers/resultsMeta/resultsMetaReducer'; @@ -15,9 +14,8 @@ import { OrderRecord } from 'redux/reducers/search/searchOrderReducer'; import { VisibilityRecord } from 'redux/reducers/search/columnVisibilityReducer'; import { mockActions, mockRedux, mockApi, mockTabCount } from './mockAwards'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('../filters/searchHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const autoTabSpy = sinon.spy(ResultsTableContainer.prototype, 'pickDefaultTab'); @@ -35,59 +33,23 @@ jest.mock('helpers/textMeasurement', () => ( } )); -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - describe('ResultsTableContainer', () => { it('should pick a default tab for awards on mount', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - mount(); - jest.runAllTicks(); - expect(autoTabSpy.callCount).toEqual(1); + autoTabSpy.reset(); + searchSpy.reset(); }); it('should pick a default tab whenever the Redux filters change', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - const container = mount(); - jest.runAllTicks(); - expect(autoTabSpy.callCount).toEqual(1); // update the filters @@ -99,24 +61,20 @@ describe('ResultsTableContainer', () => { filters: newFilters }); - jest.runAllTicks(); - // this should trigger a new API call expect(autoTabSpy.callCount).toEqual(2); - autoTabSpy.reset(); - }); - - it('should make an API call whenever the Redux table type value changes', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); + autoTabSpy.reset(); searchSpy.reset(); + }); + it('should make an API call whenever the Redux table type value changes', async () => { const container = mount(); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; expect(searchSpy.callCount).toEqual(1); @@ -129,22 +87,20 @@ describe('ResultsTableContainer', () => { meta: new MetaRecord(metaData) }); - jest.runAllTicks(); - // this should trigger a new API call expect(searchSpy.callCount).toEqual(2); + + autoTabSpy.reset(); searchSpy.reset(); }); - it('should make an API call when the Redux sort order changes', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should make an API call when the Redux sort order changes', async () => { const container = mount(); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; expect(searchSpy.callCount).toEqual(1); @@ -157,22 +113,23 @@ describe('ResultsTableContainer', () => { searchOrder: new OrderRecord(orderData) }); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; // this should trigger a new API call expect(searchSpy.callCount).toEqual(2); + + autoTabSpy.reset(); searchSpy.reset(); }); - it('should make an API call when the Redux page number changes', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should make an API call when the Redux page number changes', async () => { const container = mount(); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; expect(searchSpy.callCount).toEqual(1); @@ -187,22 +144,23 @@ describe('ResultsTableContainer', () => { meta: new MetaRecord(metaData) }); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; // this should trigger a new API call expect(searchSpy.callCount).toEqual(2); + + autoTabSpy.reset(); searchSpy.reset(); }); - it('should make an API call when columns are added or removed', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should make an API call when columns are added or removed', async () => { const container = mount(); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; expect(searchSpy.callCount).toEqual(1); @@ -216,35 +174,36 @@ describe('ResultsTableContainer', () => { searchOrder: new VisibilityRecord(columnVisibilityData) }); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; // this should trigger a new API call expect(searchSpy.callCount).toEqual(2); + + autoTabSpy.reset(); searchSpy.reset(); }); describe('updateFilters', () => { - it('should reset the page number to 1', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should reset the page number to 1', async () => { const container = shallow(); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; container.setState({ page: 5 }); container.instance().updateFilters(); expect(container.state().page).toEqual(1); - }); - it('should save a SearchObject object to state', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); + autoTabSpy.reset(); + searchSpy.reset(); + }); + it('should save a SearchObject object to state', async () => { const customFilters = Object.assign({}, mockRedux.filters, { keyword: 'blah blah' }); @@ -258,31 +217,36 @@ describe('ResultsTableContainer', () => { {...redux} />); container.instance().updateFilters(); + + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(container.state().searchParams.keyword).toEqual('blah blah'); - }); - it('will trigger an API call', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); + autoTabSpy.reset(); + searchSpy.reset(); + }); + it('will trigger an API call', async () => { const container = shallow(); searchSpy.reset(); container.instance().updateFilters(); - jest.runAllTicks(); + + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; expect(searchSpy.callCount).toEqual(1); + + autoTabSpy.reset(); searchSpy.reset(); }); }); describe('parseData', () => { - it('should parse the API response into an array of award objects', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should parse the API response into an array of award objects', async () => { const insertAction = jest.fn(); const actions = Object.assign({}, mockActions, { @@ -295,17 +259,20 @@ describe('ResultsTableContainer', () => { container.instance().parseData(mockApi.results); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(insertAction).toHaveBeenCalledTimes(1); expect(insertAction.mock.calls[0][0].type).toEqual('awards'); expect(insertAction.mock.calls[0][0].data).toHaveLength(1); + + autoTabSpy.reset(); + searchSpy.reset(); }); }); describe('switchTab', () => { - it('should change the Redux table type', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should change the Redux table type', async () => { const tableTypeAction = jest.fn(); const actions = Object.assign({}, mockActions, { @@ -318,16 +285,19 @@ describe('ResultsTableContainer', () => { container.instance().switchTab('loans'); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(tableTypeAction).toHaveBeenCalledTimes(1); expect(tableTypeAction.mock.calls[0][0]).toEqual('loans'); + + autoTabSpy.reset(); + searchSpy.reset(); }); }); describe('loadNextPage', () => { - it('should load the next page if available', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should load the next page if available', async () => { const pageNumber = jest.fn(); const actions = Object.assign({}, mockActions, { @@ -351,13 +321,16 @@ describe('ResultsTableContainer', () => { container.instance().loadNextPage(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(pageNumber).toHaveBeenCalledTimes(1); expect(pageNumber.mock.calls[0][0]).toEqual(6); - }); - it('should do nothing if there are no more pages', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); + autoTabSpy.reset(); + searchSpy.reset(); + }); + it('should do nothing if there are no more pages', async () => { const pageNumber = jest.fn(); const actions = Object.assign({}, mockActions, { @@ -381,15 +354,18 @@ describe('ResultsTableContainer', () => { container.instance().loadNextPage(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(pageNumber).toHaveBeenCalledTimes(0); + + autoTabSpy.reset(); + searchSpy.reset(); }); }); describe('parseTabCounts', () => { - it('should select the first tab (left to right) with a non-zero aggregate value', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should select the first tab (left to right) with a non-zero aggregate value', async () => { const container = shallow(); @@ -399,6 +375,9 @@ describe('ResultsTableContainer', () => { container.instance().parseTabCounts(mockTabCount); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(mockSwitchTab).toHaveBeenLastCalledWith('contracts'); // now check a second response @@ -433,12 +412,12 @@ describe('ResultsTableContainer', () => { container.instance().parseTabCounts(secondMock); expect(mockSwitchTab).toHaveBeenLastCalledWith('grants'); - }); - it('should trigger an API call for awards', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); + autoTabSpy.reset(); + searchSpy.reset(); + }); + it('should trigger an API call for awards', async () => { const container = shallow(); @@ -447,17 +426,18 @@ describe('ResultsTableContainer', () => { expect(searchSpy.callCount).toEqual(0); container.instance().parseTabCounts(mockTabCount); - jest.runAllTicks(); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(searchSpy.callCount).toEqual(1); + + autoTabSpy.reset(); searchSpy.reset(); }); }); describe('toggleColumnVisibility', () => { - it('should change the Redux column visibility', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should change the Redux column visibility', async () => { const columnVisibilityAction = jest.fn(); const actions = Object.assign({}, mockActions, { @@ -470,18 +450,21 @@ describe('ResultsTableContainer', () => { container.instance().toggleColumnVisibility('recipient_name'); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(columnVisibilityAction).toHaveBeenCalledTimes(1); expect(columnVisibilityAction.mock.calls[0][0]).toEqual({ column: "recipient_name", tableType: "contracts" }); + + autoTabSpy.reset(); + searchSpy.reset(); }); }); describe('reorderColumns', () => { - it('should change the order of the visible columns', () => { - mockSearchHelper('fetchAwardCounts', 'resolve', mockTabCount); - mockSearchHelper('performPagedSearch', 'resolve', mockApi); - + it('should change the order of the visible columns', async () => { const columnVisibilityAction = jest.fn(); const actions = Object.assign({}, mockActions, { @@ -494,10 +477,16 @@ describe('ResultsTableContainer', () => { container.instance().reorderColumns(5, 2); + await container.instance().tabCountRequest.promise; + await container.instance().searchRequest.promise; + expect(columnVisibilityAction).toHaveBeenCalledTimes(1); expect(columnVisibilityAction.mock.calls[0][0]).toEqual({ tableType: "contracts", dragIndex: 5, hoverIndex: 2 }); + + autoTabSpy.reset(); + searchSpy.reset(); }); }); }); diff --git a/tests/containers/search/visualizations/mockVisualizations.js b/tests/containers/search/visualizations/mockVisualizations.js index 8942b2855b..f7e1511bc0 100644 --- a/tests/containers/search/visualizations/mockVisualizations.js +++ b/tests/containers/search/visualizations/mockVisualizations.js @@ -20,7 +20,23 @@ export const geo = { }; export const awardingAgency = { - + page_metadata: { + page: 1, + has_next_page: false, + has_previous_page: false, + next: null, + previous: null + }, + results: [ + { + item: 'First Agency', + aggregate: '456' + }, + { + item: 'Second Agency', + aggregate: '123' + } + ] }; export const spendingByCategory = { @@ -44,11 +60,47 @@ export const spendingByCategory = { }; export const cfda = { - + page_metadata: { + page: 1, + has_next_page: false, + has_previous_page: false, + next: null, + previous: null + }, + results: [ + { + item: '93.778', + aggregate: '66681011412.00', + assistance_data__cfda__program_number: '93.778', + assistance_data__cfda__program_title: 'Medical Assistance Program' + }, + { + item: '93.774', + aggregate: '152', + assistance_data__cfda__program_number: '93.774', + assistance_data__cfda__program_title: 'Medicare_Supplementary Medical Insurance' + } + ] }; export const fundingAgency = { - + page_metadata: { + page: 1, + has_next_page: false, + has_previous_page: false, + next: null, + previous: null + }, + results: [ + { + item: 'First Agency', + aggregate: '456' + }, + { + item: 'Second Agency', + aggregate: '123' + } + ] }; export const industryCode = { diff --git a/tests/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer-test.jsx index bd544c723f..6a0c08106c 100644 --- a/tests/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer-test.jsx @@ -13,52 +13,16 @@ import { SpendingByAwardingAgencyVisualizationContainer } from 'containers/search/visualizations/rank/SpendingByAwardingAgencyVisualizationContainer'; import SpendingByAgencySection from 'components/search/visualizations/rank/sections/SpendingByAgencySection'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('./mocks/awardingAgencyHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const fetchDataSpy = sinon.spy(SpendingByAwardingAgencyVisualizationContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('SpendingByAwardingAgencyVisualizationContainer', () => { beforeAll(() => { // we need to use mount() on the container to get the lifecycle logic, but enzyme doesn't @@ -68,37 +32,12 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { mockComponent(SpendingByAgencySection); }); - it('should make an API request on mount', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); @@ -106,36 +45,11 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { // the page number should be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -146,8 +60,7 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { const container = mount(); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -160,51 +73,24 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); // the page number should still be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly restructure the API data for the rank visualization', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [{ - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 2 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); + it('should properly restructure the API data for the rank visualization', async () => { // mount the container - const container = - mount(); + const container = mount(); + + await container.instance().apiRequest.promise; - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); // validate the state contains the correctly parsed values const expectedState = { loading: false, @@ -225,33 +111,9 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { describe('nextPage', () => { it('should trigger a new API call with an incremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - // mount the container - const container = - mount(); + const container = mount(); // initial state should be page 1 expect(container.state().page).toEqual(1); @@ -269,42 +131,16 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { describe('previousPage', () => { it('should trigger a new API call with a decremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [{ - awarding_agency__toptier_agency__name: 'First Agency', - aggregate: '456' - }, - { - awarding_agency__toptier_agency__name: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 200 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container - const container = - mount(); + const container = mount(); + container.setState({ page: 5, has_previous_page: true, previous: "checksum" }); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(5); @@ -314,40 +150,14 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { }); it('should never use a page number less than 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [{ - awarding_agency__toptier_agency__name: 'First Agency', - aggregate: '456' - }, - { - awarding_agency__toptier_agency__name: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 200 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container - const container = - mount(); + const container = mount(); + container.setState({ page: 1 }); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(1); @@ -359,28 +169,6 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { describe('newSearch', () => { it('when Redux filters change, the page number should reset to 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [{ - awarding_agency__toptier_agency__name: 'First Agency', - aggregate: '456' - }, - { - awarding_agency__toptier_agency__name: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 200 - } - }; - const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -388,8 +176,9 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { }); // mount the container - const container = - mount(); + const container = mount(); + container.setState({ page: 5, has_previous_page: true, @@ -406,14 +195,13 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { // the page number should be reset to 1 expect(container.state().page).toEqual(1); - }); }); describe('changeScope', () => { it('should change the agency scope to the provided value', () => { - const container = - mount(); + const container = mount(); // the default scope should be toptier expect(container.state().agencyScope).toEqual('toptier'); @@ -424,8 +212,8 @@ describe('SpendingByAwardingAgencyVisualizationContainer', () => { }); it('should reset the page number to 1 when the agency scope changes', () => { - const container = - mount(); + const container = mount(); container.setState({ page: 5 }); diff --git a/tests/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer-test.jsx index b8145862e3..b76917daf0 100644 --- a/tests/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer-test.jsx @@ -13,53 +13,17 @@ import { SpendingByCFDAVisualizationContainer } from 'containers/search/visualizations/rank/SpendingByCFDAVisualizationContainer'; import SpendingByCFDASection from 'components/search/visualizations/rank/sections/SpendingByCFDASection'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('./mocks/cfdaHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const fetchDataSpy = sinon.spy(SpendingByCFDAVisualizationContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('SpendingByCFDAVisualizationContainer', () => { beforeAll(() => { // we need to use mount() on the container to get the lifecycle logic, but enzyme doesn't @@ -69,42 +33,13 @@ describe('SpendingByCFDAVisualizationContainer', () => { mockComponent(SpendingByCFDASection); }); - it('should make an API request on mount', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: '93.778', - aggregate: '66681011412.00', - assistance_data__cfda__program_number: '93.778', - assistance_data__cfda__program_title: 'Medical Assistance Program' - }, - { - item: '93.774', - aggregate: '152', - assistance_data__cfda__program_number: '93.774', - assistance_data__cfda__program_title: 'Medicare_Supplementary Medical Insurance' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); @@ -112,40 +47,11 @@ describe('SpendingByCFDAVisualizationContainer', () => { // the page number should be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: '93.778', - aggregate: '66681011412.00', - award__transaction__assistance_data__cfda__program_number: '93.778', - award__transaction__assistance_data__cfda__program_title: 'Medical Assistance Program' - }, - { - item: '93.774', - aggregate: '152', - award__transaction__assistance_data__cfda__program_number: '93.774', - award__transaction__assistance_data__cfda__program_title: 'Medicare_Supplementary Medical Insurance' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -157,8 +63,7 @@ describe('SpendingByCFDAVisualizationContainer', () => { mount(); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -171,55 +76,25 @@ describe('SpendingByCFDAVisualizationContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); // the page number should still be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly restructure the API data for the rank visualization', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: '93.778', - aggregate: '66681011412.00', - assistance_data__cfda__program_number: '93.778', - assistance_data__cfda__program_title: 'Medical Assistance Program' - }, - { - item: '93.774', - aggregate: '152', - assistance_data__cfda__program_number: '93.774', - assistance_data__cfda__program_title: 'Medicare_Supplementary Medical Insurance' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); + it('should properly restructure the API data for the rank visualization', async () => { // mount the container const container = mount(); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); + await container.instance().apiRequest.promise; + // validate the state contains the correctly parsed values const expectedState = { loading: false, @@ -241,20 +116,6 @@ describe('SpendingByCFDAVisualizationContainer', () => { describe('nextPage', () => { it('should trigger a new API call with an incremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount( { describe('previousPage', () => { it('should trigger a new API call with a decremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount(); + container.setState({ page: 5, has_previous_page: true, previous: "checksum" }); - // wait for the SearchHelper promises to resolve - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(5); @@ -311,30 +157,15 @@ describe('SpendingByCFDAVisualizationContainer', () => { }); it('should never use a page number less than 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); // mount the container const container = mount(); + container.setState({ page: 1 }); - // wait for the SearchHelper promises to resolve - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(1); @@ -356,6 +187,7 @@ describe('SpendingByCFDAVisualizationContainer', () => { const container = mount(); + container.setState({ page: 5, has_previous_page: true, diff --git a/tests/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer-test.jsx b/tests/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer-test.jsx index dea0bef364..2bdcca866e 100644 --- a/tests/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer-test.jsx +++ b/tests/containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer-test.jsx @@ -13,52 +13,16 @@ import { SpendingByFundingAgencyVisualizationContainer } from 'containers/search/visualizations/rank/SpendingByFundingAgencyVisualizationContainer'; import SpendingByAgencySection from 'components/search/visualizations/rank/sections/SpendingByAgencySection'; -import * as SearchHelper from 'helpers/searchHelper'; import { defaultFilters } from '../../../../testResources/defaultReduxFilters'; import { mockComponent, unmockComponent } from '../../../../testResources/mockComponent'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); +jest.mock('helpers/searchHelper', () => require('./mocks/fundingAgencyHelper')); +jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // spy on specific functions inside the component const fetchDataSpy = sinon.spy(SpendingByFundingAgencyVisualizationContainer.prototype, 'fetchData'); -// we don't want to actually hit the API because tests should be fully controlled, so we will mock -// the SearchHelper functions -const mockSearchHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - SearchHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockSearchHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/searchHelper'); -}; - describe('SpendingByFundingAgencyVisualizationContainer', () => { beforeAll(() => { // we need to use mount() on the container to get the lifecycle logic, but enzyme doesn't @@ -68,38 +32,13 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { mockComponent(SpendingByAgencySection); }); - it('should make an API request on mount', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performTransactionsTotalSearch', 'resolve', apiResponse); - + it('should make an API request on mount', async () => { // mount the container const container = mount(); - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); + await container.instance().apiRequest.promise; // everything should be updated now expect(fetchDataSpy.callCount).toEqual(1); @@ -107,36 +46,11 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { // the page number should be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); - it('should make an API request when the Redux filters change', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [ - { - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); - + it('should make an API request when the Redux filters change', async () => { const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -148,8 +62,7 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { mount(); - // wait for the first SearchHelper call to finish - jest.runAllTicks(); + await container.instance().apiRequest.promise; // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(1); @@ -162,52 +75,25 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { reduxFilters: secondFilters }); - // wait for the second SearchHelper call to finish - jest.runAllTicks(); // the first API call should have been called expect(fetchDataSpy.callCount).toEqual(2); // the page number should still be equal to 1 expect(container.state().page).toEqual(1); - // reset the mocks and spies - unmockSearchHelper(); + // reset the spy fetchDataSpy.reset(); }); describe('parseData', () => { - it('should properly restructure the API data for the rank visualization', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: false, - has_previous_page: false, - next: null, - previous: null - }, - results: [{ - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 2 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); + it('should properly restructure the API data for the rank visualization', async () => { // mount the container const container = mount(); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); + await container.instance().apiRequest.promise; + // validate the state contains the correctly parsed values const expectedState = { loading: false, @@ -228,30 +114,6 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { describe('nextPage', () => { it('should trigger a new API call with an incremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [ - { - item: 'First Agency', - aggregate: '456' - }, - { - item: 'Second Agency', - aggregate: '123' - } - ] - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); - // mount the container const container = mount( { describe('previousPage', () => { it('should trigger a new API call with a decremented page number', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [{ - funding_agency__toptier_agency__name: 'First Agency', - aggregate: '456' - }, - { - funding_agency__toptier_agency__name: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 200 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); // mount the container const container = mount(); + container.setState({ page: 5, has_previous_page: true, previous: "checksum" }); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(5); @@ -319,41 +155,15 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { }); it('should never use a page number less than 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [{ - funding_agency__toptier_agency__name: 'First Agency', - aggregate: '456' - }, - { - funding_agency__toptier_agency__name: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 200 - } - }; - - // mock the search helper to resolve with the mocked response - mockSearchHelper('performCategorySearch', 'resolve', apiResponse); // mount the container const container = mount(); + container.setState({ page: 1 }); - // wait for the SearchHelper promises to resolve - jest.runAllTicks(); - // we have simulated a starting state of page 5 expect(container.state().page).toEqual(1); @@ -365,28 +175,6 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { describe('newSearch', () => { it('when Redux filters change, the page number should reset to 1', () => { - // create a mock API response - const apiResponse = { - page_metadata: { - page: 1, - has_next_page: true, - has_previous_page: false, - next: "checksum", - previous: null - }, - results: [{ - funding_agency__toptier_agency__name: 'First Agency', - aggregate: '456' - }, - { - funding_agency__toptier_agency__name: 'Second Agency', - aggregate: '123' - }], - total_metadata: { - count: 200 - } - }; - const initialFilters = Object.assign({}, defaultFilters); const secondFilters = Object.assign({}, defaultFilters, { timePeriodType: 'fy', @@ -397,6 +185,7 @@ describe('SpendingByFundingAgencyVisualizationContainer', () => { const container = mount(); + container.setState({ page: 5, has_previous_page: true, diff --git a/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js b/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js index eb4f7d9f9c..d51b31232e 100644 --- a/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js +++ b/tests/containers/search/visualizations/rank/mocks/awardingAgencyHelper.js @@ -1,3 +1,15 @@ -/** - * Created by michaelbray on 7/16/17. - */ +import { awardingAgency } from '../../mockVisualizations'; + +// Fetch Transactions Total +export const performTransactionsTotalSearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: awardingAgency + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/search/visualizations/rank/mocks/cdfaHelper.js b/tests/containers/search/visualizations/rank/mocks/cdfaHelper.js deleted file mode 100644 index eb4f7d9f9c..0000000000 --- a/tests/containers/search/visualizations/rank/mocks/cdfaHelper.js +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Created by michaelbray on 7/16/17. - */ diff --git a/tests/containers/search/visualizations/rank/mocks/cfdaHelper.js b/tests/containers/search/visualizations/rank/mocks/cfdaHelper.js new file mode 100644 index 0000000000..67519b9c20 --- /dev/null +++ b/tests/containers/search/visualizations/rank/mocks/cfdaHelper.js @@ -0,0 +1,15 @@ +import { cfda } from '../../mockVisualizations'; + +// Fetch Transactions Total +export const performTransactionsTotalSearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: cfda + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js b/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js index eb4f7d9f9c..22fd86f0d7 100644 --- a/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js +++ b/tests/containers/search/visualizations/rank/mocks/fundingAgencyHelper.js @@ -1,3 +1,15 @@ -/** - * Created by michaelbray on 7/16/17. - */ +import { fundingAgency } from '../../mockVisualizations'; + +// Fetch Categories +export const performCategorySearch = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: fundingAgency + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/redux/reducers/search/mock/mockRecipient.js b/tests/redux/reducers/search/mock/mockRecipient.js deleted file mode 100644 index 546840c6ff..0000000000 --- a/tests/redux/reducers/search/mock/mockRecipient.js +++ /dev/null @@ -1,6 +0,0 @@ -export const mockLocationAutocomplete = [{ - place_type: "CITY", - matched_ids: [22516, 23056], - place: "MCLEAN", - parent: null -}]; From ff2148171e174cd0a0ede8a1ee9738aa10a637f5 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Mon, 17 Jul 2017 16:29:36 -0400 Subject: [PATCH 24/97] Handle search input text with mock data --- .../AgencyLandingResultsSection.jsx | 14 +- .../agencyLanding/AgencyLandingSearchBar.jsx | 12 +- .../table/AgencyLandingTable.jsx | 6 +- .../agencyLanding/AgencyLandingContainer.jsx | 203 ++++++++++++++---- .../agencyLanding/agencyLandingActions.js | 5 + .../agencyLanding/agencyLandingReducer.js | 10 +- 6 files changed, 201 insertions(+), 49 deletions(-) diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx index 172e5a2020..7296296942 100644 --- a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -12,7 +12,8 @@ import AgencyLandingTable from './table/AgencyLandingTable'; const propTypes = { inFlight: React.PropTypes.bool, results: React.PropTypes.array, - columns: React.PropTypes.array + columns: React.PropTypes.array, + agencySearchString: React.PropTypes.string }; export default class AgencyLandingResultsSection extends React.Component { @@ -51,7 +52,16 @@ export default class AgencyLandingResultsSection extends React.Component { } else if (this.props.results.length === 0) { // no results - message = ; + if (this.props.agencySearchString) { + message = ( +
+ No results found for “ {this.props.agencySearchString} ”. +
+ ); + } + else { + message = ; + } } return ( diff --git a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx index 042c2acb84..a0a021ccf3 100644 --- a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx +++ b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx @@ -7,10 +7,14 @@ import React from 'react'; import { Search } from 'components/sharedComponents/icons/Icons'; +const propTypes = { + handleTextInput: React.PropTypes.func.isRequired +}; + export default class AgencyLandingSearchBar extends React.Component { - // constructor(props) { - // super(props); - // } + onChange(e) { + this.props.handleTextInput(e); + } render() { return ( @@ -19,6 +23,7 @@ export default class AgencyLandingSearchBar extends React.Component { From b294c90b97e80b887c539662387c3a07ac06cbc8 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 27 Jul 2017 13:54:49 -0400 Subject: [PATCH 59/97] Enable link in nav --- src/js/components/sharedComponents/header/ProfileButton.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/js/components/sharedComponents/header/ProfileButton.jsx b/src/js/components/sharedComponents/header/ProfileButton.jsx index 3579d323a0..56e8865853 100644 --- a/src/js/components/sharedComponents/header/ProfileButton.jsx +++ b/src/js/components/sharedComponents/header/ProfileButton.jsx @@ -66,10 +66,8 @@ export default class ProfileButton extends React.Component {
  • Agencies -
  • From 9dc677483852e7c76f287787b8fb6e9bfe606cbe Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Thu, 27 Jul 2017 15:16:13 -0400 Subject: [PATCH 60/97] Missed filename --- src/js/redux/reducers/search/searchFiltersReducer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/redux/reducers/search/searchFiltersReducer.js b/src/js/redux/reducers/search/searchFiltersReducer.js index 009de598ea..e52a9909da 100644 --- a/src/js/redux/reducers/search/searchFiltersReducer.js +++ b/src/js/redux/reducers/search/searchFiltersReducer.js @@ -12,7 +12,7 @@ import * as RecipientFilterFunctions from './filters/recipientFilterFunctions'; import * as AwardIDFilterFunctions from './filters/awardIDFilterFunctions'; import * as AwardAmountFilterFunctions from './filters/awardAmountFilterFunctions'; import * as BudgetCategoryFilterFunctions from './filters/budgetCategoryFilterFunctions'; -import * as OtherFilterFunctions from './filters/otherFilterFunctions'; +import * as OtherFilterFunctions from './filters/OtherFilterFunctions'; // update this version when changes to the reducer structure are made // frontend will reject inbound hashed search filter sets with different versions because the From a3e14ada1925d95fa5cc45411050acd4bc9a1870 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 27 Jul 2017 16:19:07 -0400 Subject: [PATCH 61/97] Added tooltip --- .../results/visualizations/time/time.scss | 34 ++++++- .../time/AccountTimeVisualizationSection.jsx | 4 +- .../visualizations/time/TimeTooltip.jsx | 81 +++++++++++++++++ .../visualizations/time/TimeVisualization.jsx | 53 ++++++----- .../visualizations/time/TooltipItem.jsx | 29 ++++++ .../time/chart/BarChartStacked.jsx | 89 +++++++++++++++---- .../time/chart/StackedBarGroup.jsx | 37 +++++++- .../AccountTimeVisualizationContainer.jsx | 40 ++++++--- 8 files changed, 309 insertions(+), 58 deletions(-) create mode 100644 src/js/components/account/visualizations/time/TimeTooltip.jsx create mode 100644 src/js/components/account/visualizations/time/TooltipItem.jsx diff --git a/src/_scss/pages/account/results/visualizations/time/time.scss b/src/_scss/pages/account/results/visualizations/time/time.scss index b39d87112c..561484607e 100644 --- a/src/_scss/pages/account/results/visualizations/time/time.scss +++ b/src/_scss/pages/account/results/visualizations/time/time.scss @@ -1,9 +1,39 @@ .results-visualization-time-section { @import "./_topSection"; @import "./chart/barChart"; - .visualization-tooltip { - @import "components/visualizations/tooltip/_tooltip"; + + @import "components/visualizations/tooltip/_tooltip"; + + .tooltip-items { + @include unstyled-list; + + li { + margin-top: rem(15); + &:first-child { + margin-top: 0; + } + + .item-value { + border-bottom: 1px solid #D5D6D8; + font-size: rem(30); + font-weight: $font-light; + line-height: rem(30); + padding: 0 0 rem(10) 0; + } + .item-label { + font-size: $small-font-size; + font-weight: $font-normal; + line-height: rem(23); + padding: rem(5) 0 0 0; + text-align: center; + } + } } + + .results-visualization-time-container { + position: relative; + } + .results-visualization-message { margin-top: rem(10); font-size: $small-font-size; diff --git a/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx b/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx index 82dcea1bb8..19d4ba8ee6 100644 --- a/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx +++ b/src/js/components/account/visualizations/time/AccountTimeVisualizationSection.jsx @@ -13,6 +13,7 @@ import TimeVisualization from './TimeVisualization'; const propTypes = { data: PropTypes.object, + loading: PropTypes.bool, visualizationPeriod: PropTypes.string, changePeriod: PropTypes.func, hasFilteredObligated: PropTypes.bool @@ -93,7 +94,8 @@ export default class AccountTimeVisualizationSection extends React.Component {
diff --git a/src/js/components/account/visualizations/time/TimeTooltip.jsx b/src/js/components/account/visualizations/time/TimeTooltip.jsx new file mode 100644 index 0000000000..782f1739a5 --- /dev/null +++ b/src/js/components/account/visualizations/time/TimeTooltip.jsx @@ -0,0 +1,81 @@ +/** + * Tooltip.jsx + * Created by Kevin Li 7/27/17 + */ + +import React from 'react'; +import PropTypes from 'prop-types'; + +import TooltipItem from './TooltipItem'; + +const propTypes = { + xValue: PropTypes.string, + values: PropTypes.array, + position: PropTypes.object, + width: PropTypes.number, + height: PropTypes.number +}; + +export default class TimeTooltip extends React.Component { + componentDidMount() { + this.positionTooltip(); + } + + positionTooltip() { + // we need to wait for the tooltip to render before we can full position it due to its + // dynamic width + const tooltipWidth = this.div.offsetWidth; + const windowWidth = window.innerWidth; + + // determine the tooltip direction + let direction = 'left'; + // allow 20px padding + if (tooltipWidth + this.props.position.x >= windowWidth - 20) { + direction = 'right'; + } + + // offset the tooltip position to account for its arrow/pointer + let offset = 9; + if (direction === 'right') { + offset = -9 - tooltipWidth; + } + + this.div.style.transform = + `translate(${this.props.position.x + offset}px,${this.props.position.y}px)`; + this.div.className = `tooltip ${direction}`; + this.pointerDiv.className = `tooltip-pointer ${direction}`; + } + + render() { + const items = this.props.values.map((item) => ( + + )); + + return ( +
{ + this.div = div; + }}> +
{ + this.pointerDiv = div; + }} /> +
+ {this.props.xValue} +
+
+
    + {items} +
+
+
+ ); + } +} + +TimeTooltip.propTypes = propTypes; diff --git a/src/js/components/account/visualizations/time/TimeVisualization.jsx b/src/js/components/account/visualizations/time/TimeVisualization.jsx index 90d9106f13..3284542d13 100644 --- a/src/js/components/account/visualizations/time/TimeVisualization.jsx +++ b/src/js/components/account/visualizations/time/TimeVisualization.jsx @@ -8,12 +8,9 @@ import PropTypes from 'prop-types'; import ChartMessage from 'components/search/visualizations/time/TimeVisualizationChartMessage'; import BarChartStacked from './chart/BarChartStacked'; +import TimeTooltip from './TimeTooltip'; const defaultProps = { - groups: [], - xSeries: [], - ySeries: [], - stacks: [], width: 0, height: 280 }; @@ -32,10 +29,7 @@ const defaultProps = { const propTypes = { width: PropTypes.number, height: PropTypes.number, - xSeries: PropTypes.array, - ySeries: PropTypes.array, - allY: PropTypes.array, - stacks: PropTypes.array, + data: PropTypes.object, loading: PropTypes.bool, hasFilteredObligated: PropTypes.bool }; @@ -53,18 +47,32 @@ export default class TimeVisualization extends React.Component { }; this.showTooltip = this.showTooltip.bind(this); + this.hideTooltip = this.hideTooltip.bind(this); + this.toggleTooltip = this.toggleTooltip.bind(this); } - showTooltip(data, x, y) { - console.log(data); + showTooltip(data) { this.setState({ showTooltip: true, - tooltipData: data, - tooltipX: x, - tooltipY: y + tooltipData: data }); } + hideTooltip() { + this.setState({ + showTooltip: false + }); + } + + toggleTooltip(data) { + if (this.state.showTooltip) { + this.hideTooltip(); + } + else { + this.showTooltip(data); + } + } + render() { let chart = (); let legend = []; @@ -117,29 +125,30 @@ export default class TimeVisualization extends React.Component { // API request is still pending chart = (); } - else if (this.props.xSeries.length > 0) { + else if (this.props.data.xSeries.length > 0) { // only mount the chart component if there is data to display chart = (); + showTooltip={this.showTooltip} + hideTooltip={this.hideTooltip} + toggleTooltip={this.toggleTooltip} />); } let tooltip = null; if (this.state.showTooltip) { - tooltip = ''; + tooltip = (); } return (
- {chart} {tooltip} + {chart}
); } diff --git a/src/js/components/account/visualizations/time/TooltipItem.jsx b/src/js/components/account/visualizations/time/TooltipItem.jsx new file mode 100644 index 0000000000..8a2eaa86e6 --- /dev/null +++ b/src/js/components/account/visualizations/time/TooltipItem.jsx @@ -0,0 +1,29 @@ +/** + * TooltipItem.jsx + * Created by Kevin Li 7/27/17 + */ + +import React from 'react'; +import PropTypes from 'prop-types'; + +const propTypes = { + value: PropTypes.string, + label: PropTypes.string +}; + +const TooltipItem = (props) => ( +
  • +
    +
    + {props.value} +
    +
    + {props.label} +
    +
    +
  • +); + +TooltipItem.propTypes = propTypes; + +export default TooltipItem; diff --git a/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx b/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx index ef0259c3bf..7ea16e3c5e 100644 --- a/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx +++ b/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx @@ -22,12 +22,12 @@ import StackedBarGroup from './StackedBarGroup'; const propTypes = { height: PropTypes.number, width: PropTypes.number, - allY: PropTypes.array, - xSeries: PropTypes.array, - ySeries: PropTypes.array, - stacks: PropTypes.array, + data: PropTypes.object, padding: PropTypes.object, - legend: PropTypes.array + legend: PropTypes.array, + showTooltip: PropTypes.func, + hideTooltip: PropTypes.func, + toggleTooltip: PropTypes.func }; /* eslint-enable react/no-unused-prop-types */ @@ -53,7 +53,12 @@ export default class BarChartStacked extends React.Component { } componentWillReceiveProps(nextProps) { - this.buildVirtualChart(nextProps); + if (nextProps.data !== this.props.data) { + this.buildVirtualChart(nextProps); + } + else if (nextProps.width !== this.props.width || nextProps.height !== this.props.height) { + this.buildVirtualChart(nextProps); + } } buildVirtualChart(props) { @@ -61,10 +66,10 @@ export default class BarChartStacked extends React.Component { const values = { width: props.width, height: props.height, - allY: props.allY, - xSeries: props.xSeries, - ySeries: props.ySeries, - stacks: props.stacks + allY: props.data.allY, + xSeries: props.data.xSeries, + ySeries: props.data.ySeries, + stacks: props.data.stacks }; // calculate what the visible area of the chart itself will be (excluding the axes and their @@ -254,27 +259,55 @@ ${xAxis.items[0].label} to ${xAxis.items[xAxis.items.length - 1].label}.`; const item = { xPos, xValue: x, - stack: [] + stack: [], + hitzone: { + width: barWidth, + height: values.graphHeight + }, + tooltip: { + values: [], + xValue: x, + position: { + x: xPos + (barWidth / 2) + values.padding.left, + y: 0 + } + } }; + // build the tooltip data + const tooltip = []; + let maxY = 0; + + // iterate through each stacked item values.stacks.forEach((stack) => { + // get the data for the stacked item const data = y[stack.name]; - // offset the x position by 20px to account for padding between bars + // determine the Y position of the top of the bar let yPos = values.yScale(data.top); let height = 0; if (stack.type === 'bar') { + // bars have height, so calculate it by getting the Y position of the bottom of + // the bar and taking the difference height = values.yScale(data.bottom) - yPos; + // however, if the bar shows a negative value but extends to a 0 or positive + // value, the "top" of the bar is actually visually the bottom - and the + // "bottom" bar (the visual top) is the X axis if (data.top < 0 && data.bottom >= 0) { yPos = zeroY; height = values.yScale(data.top) - zeroY; } else if (data.top < 0) { + // if the bar shows a negative value and it is entirely negative (the + // two endpoints of the bar are both in the negative region), use the + // least negative value as the top point of the bar and the most negative + // value as the bottom (and height is again the difference between the two) yPos = values.yScale(Math.max(data.bottom, data.top)); height = values.yScale(Math.min(data.bottom, data.top)) - yPos; } } + // merge the positioning of the stacked item with its metadata const element = Object.assign({}, stack, { height, width: barWidth, @@ -285,11 +318,27 @@ ${xAxis.items[0].label} to ${xAxis.items[xAxis.items.length - 1].label}.`; description: data.description }); item.stack.push(element); + + // add the value to the tooltip + tooltip.push({ + label: data.description, + value: MoneyFormatter.formatMoney(data.value), + type: stack.name + }); + + // get the highest Y position for the tooltip + if (yPos > maxY) { + maxY = yPos; + } }); // reverse the array so that the first elements are rendered last (in front) item.stack.reverse(); + // update the tooltip values (this won't be reversed) + item.tooltip.values = tooltip; + item.tooltip.position.y = (maxY / 2); + // draw a bar for each item body.items.push(item); }); @@ -298,20 +347,23 @@ ${xAxis.items[0].label} to ${xAxis.items[xAxis.items.length - 1].label}.`; } render() { - console.log("RENDER"); + // the chart hasn't been created yet, so don't render anything if (!this.state.chartReady) { return null; } - // add 20px to the top of the chart to avoid cutting off label text - // wrap the chart contents in a group and transform it down 20px to avoid impacting - // positioning calculations const body = this.state.virtualChart.body.items.map((item) => ( + key={item.xValue} + showTooltip={this.props.showTooltip} + hideTooltip={this.props.hideTooltip} + toggleTooltip={this.props.toggleTooltip} /> )); + // add 20px to the top of the chart to avoid cutting off label text + // wrap the chart contents in a group and transform it down 20px to avoid impacting + // positioning calculations return (
    + transform={`translate(${this.state.virtualChart.body.group.x},\ +${this.state.virtualChart.body.group.y})`}> {body} diff --git a/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx b/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx index 2f311fcb26..8aeca205df 100644 --- a/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx +++ b/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx @@ -11,10 +11,35 @@ import OutlayLine from './OutlayLine'; const propTypes = { xPos: PropTypes.number, - stack: PropTypes.array + stack: PropTypes.array, + hitzone: PropTypes.object, + tooltip: PropTypes.object, + showTooltip: PropTypes.func, + hideTooltip: PropTypes.func, + toggleTooltip: PropTypes.func }; export default class StackedBarGroup extends React.Component { + constructor(props) { + super(props); + + this.mouseEntered = this.mouseEntered.bind(this); + this.mouseExited = this.mouseExited.bind(this); + this.barTouched = this.barTouched.bind(this); + } + + mouseEntered() { + this.props.showTooltip(this.props.tooltip); + } + + mouseExited() { + this.props.hideTooltip(); + } + + barTouched() { + this.props.toggleTooltip(this.props.tooltip); + } + render() { const items = this.props.stack.map((item) => { if (item.type === 'bar') { @@ -33,6 +58,16 @@ export default class StackedBarGroup extends React.Component { className="bar-group" transform={`translate(${this.props.xPos},0)`}> {items} + ); } diff --git a/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx b/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx index b23198796c..b94479b3b6 100644 --- a/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx +++ b/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx @@ -8,6 +8,7 @@ import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; +import { Record } from 'immutable'; import { isEqual } from 'lodash'; @@ -20,24 +21,29 @@ import * as accountFilterActions from 'redux/actions/account/accountFilterAction import AccountSearchBalanceOperation from 'models/account/queries/AccountSearchBalanceOperation'; import AccountSearchCategoryOperation from 'models/account/queries/AccountSearchCategoryOperation'; -import { balanceFields, balanceFieldsFiltered, balanceFieldsNonfiltered } from 'dataMapping/accounts/accountFields'; +import { balanceFields, balanceFieldsFiltered, balanceFieldsNonfiltered } from + 'dataMapping/accounts/accountFields'; const propTypes = { reduxFilters: PropTypes.object, account: PropTypes.object }; -export class AccountTimeVisualizationSectionContainer extends React.Component { +// create an Immuatable Record object to guarantee the existance of required visualization fields +const VisData = Record({ + xSeries: [], + ySeries: [], + allY: [], + stacks: [] +}); + +export class AccountTimeVisualizationSectionContainer extends React.PureComponent { constructor(props) { super(props); this.state = { loading: true, - groups: [], - xSeries: [], - ySeries: [], - allY: [], - stacks: [], + data: new VisData(), visualizationPeriod: 'year', hasFilteredObligated: false }; @@ -277,19 +283,19 @@ export class AccountTimeVisualizationSectionContainer extends React.Component { bottom: 0, top: obligatedFiltered, value: obligatedFiltered, - description: 'Obligated balance (filtered)' + description: 'Obligations Incurred (Filtered)' }, obligatedOther: { bottom: obligatedFiltered, top: obligatedFiltered + obligatedOther, value: obligatedOther, - description: 'Obligated balance (excluded from filter)' + description: 'Obligations Incurred (Other)' }, unobligated: { bottom: budgetAuthority - unobligated, top: budgetAuthority, value: unobligated, - description: 'Unobligated balance' + description: 'Unobligated Balance' }, outlay: { bottom: outlay, @@ -307,7 +313,7 @@ export class AccountTimeVisualizationSectionContainer extends React.Component { bottom: 0, top: yData[quarterYear].obligated, value: yData[quarterYear].obligated, - description: 'Obligated balance' + description: 'Obligations Incurred' }, unobligated: { bottom: yData[quarterYear].obligated, @@ -374,11 +380,16 @@ export class AccountTimeVisualizationSectionContainer extends React.Component { ]; } - this.setState({ + // combine all the visualization chart data into a single Immutable object + const visualizationData = new VisData({ xSeries, ySeries, allY, - stacks, + stacks + }); + + this.setState({ + data: visualizationData, loading: false }); } @@ -386,7 +397,8 @@ export class AccountTimeVisualizationSectionContainer extends React.Component { render() { return ( From febfbe380f45d75dd33f1e3401abea5fcb7afde7 Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Thu, 27 Jul 2017 16:52:24 -0400 Subject: [PATCH 62/97] Separating indecies additions. Removing accidentally added file. --- .../search/filters/cfda/CFDAListContainer.jsx | 5 +- .../filters/naics/NAICSListContainer.jsx | 3 +- .../reducers/search/CFDAListContainer.jsx | 179 ------------------ 3 files changed, 5 insertions(+), 182 deletions(-) delete mode 100644 tests/redux/reducers/search/CFDAListContainer.jsx diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index f722499e93..3a03286456 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -4,12 +4,12 @@ **/ import React from 'react'; -import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, upperCase, omit, differenceWith, slice } from 'lodash'; import { isCancel } from 'axios'; import { Search } from 'js-search'; +import PropTypes from 'prop-types'; import * as SearchHelper from 'helpers/searchHelper'; import * as autocompleteActions from 'redux/actions/search/autocompleteActions'; @@ -95,7 +95,8 @@ export class CFDAListContainer extends React.Component { const data = res.data.results; let autocompleteData = []; const search = new Search('program_number'); - search.addIndex(['program_number', 'program_title']); + search.addIndex(['program_number']); + search.addIndex(['program_title']); search.addDocuments(data); const results = search.search(this.state.cfdaSearchString); let improvedResults = slice(results, 0, 10); diff --git a/src/js/containers/search/filters/naics/NAICSListContainer.jsx b/src/js/containers/search/filters/naics/NAICSListContainer.jsx index edfea0bf53..c0511d5ead 100644 --- a/src/js/containers/search/filters/naics/NAICSListContainer.jsx +++ b/src/js/containers/search/filters/naics/NAICSListContainer.jsx @@ -94,7 +94,8 @@ export class NAICSListContainer extends React.Component { const data = res.data.results; let autocompleteData = []; const search = new Search('naics'); - search.addIndex(['naics', 'naics_description']); + search.addIndex(['naics']); + search.addIndex(['naics_description']); search.addDocuments(data); const results = search.search(this.state.cfdaSearchString); let improvedResults = slice(results, 0, 10); diff --git a/tests/redux/reducers/search/CFDAListContainer.jsx b/tests/redux/reducers/search/CFDAListContainer.jsx deleted file mode 100644 index f722499e93..0000000000 --- a/tests/redux/reducers/search/CFDAListContainer.jsx +++ /dev/null @@ -1,179 +0,0 @@ -/** -* CFDAListContainer.jsx -* Created by Emily Gullo 07/10/2017 -**/ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { isEqual, upperCase, omit, differenceWith, slice } from 'lodash'; -import { isCancel } from 'axios'; -import { Search } from 'js-search'; - -import * as SearchHelper from 'helpers/searchHelper'; -import * as autocompleteActions from 'redux/actions/search/autocompleteActions'; - -import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete'; - -const propTypes = { - selectCFDA: PropTypes.func, - setAutocompleteCFDA: PropTypes.func, - selectedCFDA: PropTypes.object, - autocompleteCFDA: PropTypes.array -}; - -export class CFDAListContainer extends React.Component { - constructor(props) { - super(props); - - this.state = { - cfdaSearchString: '', - autocompleteCFDA: [], - noResults: false - }; - - this.handleTextInput = this.handleTextInput.bind(this); - this.clearAutocompleteSuggestions = this.clearAutocompleteSuggestions.bind(this); - this.timeout = null; - } - - componentDidMount() { - this.parseAutocompleteCFDA(this.props.autocompleteCFDA); - } - - componentWillReceiveProps(nextProps) { - if (!isEqual(nextProps.autocompleteCFDA, this.props.autocompleteCFDA)) { - this.parseAutocompleteCFDA(nextProps.autocompleteCFDA); - } - } - - parseAutocompleteCFDA(cfda) { - const values = []; - if (cfda && cfda.length > 0) { - cfda.forEach((item) => { - const title = item.program_number; - const subtitle = upperCase(item.program_title); - - values.push({ - title, - subtitle, - data: item - }); - }); - } - - this.setState({ - autocompleteCFDA: values - }); - } - - queryAutocompleteCFDA(input) { - this.setState({ - noResults: false - }); - - // Only search if input is 2 or more characters - if (input.length >= 2) { - this.setState({ - cfdaSearchString: input - }); - - if (this.cfdaSearchRequest) { - // A request is currently in-flight, cancel it - this.cfdaSearchRequest.cancel(); - } - - const cfdaSearchParams = { - search_text: this.state.cfdaSearchString - }; - - this.cfdaSearchRequest = SearchHelper.fetchCFDA(cfdaSearchParams); - - this.cfdaSearchRequest.promise - .then((res) => { - const data = res.data.results; - let autocompleteData = []; - const search = new Search('program_number'); - search.addIndex(['program_number', 'program_title']); - search.addDocuments(data); - const results = search.search(this.state.cfdaSearchString); - let improvedResults = slice(results, 0, 10); - - // Remove 'identifier' from selected cfdas to enable comparison - improvedResults = this.props.selectedCFDA.toArray() - .map((cfda) => omit(cfda, 'identifier')); - - // Filter out any selected cfdas that may be in the result set - if (improvedResults && improvedResults.length > 0) { - autocompleteData = differenceWith(data, improvedResults, isEqual); - } - else { - autocompleteData = data; - } - - this.setState({ - noResults: autocompleteData.length === 0 - }); - - // Add search results to Redux - this.props.setAutocompleteCFDA(autocompleteData); - }) - .catch((err) => { - if (!isCancel(err)) { - this.setState({ - noResults: true - }); - } - }); - } - else if (this.cfdaSearchRequest) { - // A request is currently in-flight, cancel it - this.cfdaSearchRequest.cancel(); - } - } - - clearAutocompleteSuggestions() { - this.props.setAutocompleteCFDA([]); - } - - handleTextInput(cfdaInput) { - // Clear existing cfdas to ensure user can't select an old or existing one - this.props.setAutocompleteCFDA([]); - - // Grab input, clear any exiting timeout - const input = cfdaInput.target.value; - window.clearTimeout(this.timeout); - - // Perform search if user doesn't type again for 300ms - this.timeout = window.setTimeout(() => { - this.queryAutocompleteCFDA(input); - }, 300); - } - - render() { - return ( - { - this.cfdaList = input; - }} - clearAutocompleteSuggestions={this.clearAutocompleteSuggestions} - noResults={this.state.noResults} /> - ); - } - -} - -export default connect( - (state) => ({ autocompleteCFDA: state.autocompleteCFDA }), - (dispatch) => bindActionCreators(autocompleteActions, dispatch) -)(CFDAListContainer); - -CFDAListContainer.propTypes = propTypes; From a10d1df4d048dc90b39eb9d933889914f0a56cfe Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Thu, 27 Jul 2017 17:14:39 -0400 Subject: [PATCH 63/97] Updating formatting of suggestions --- src/js/containers/search/filters/cfda/CFDAListContainer.jsx | 4 ++-- .../containers/search/filters/naics/NAICSListContainer.jsx | 6 ++---- src/js/containers/search/filters/psc/PSCListContainer.jsx | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index 3a03286456..7c30744716 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -52,8 +52,8 @@ export class CFDAListContainer extends React.Component { const values = []; if (cfda && cfda.length > 0) { cfda.forEach((item) => { - const title = item.program_number; - const subtitle = upperCase(item.program_title); + const title = `${item.program_number} - ${item.program_title}`; + const subtitle = ''; values.push({ title, diff --git a/src/js/containers/search/filters/naics/NAICSListContainer.jsx b/src/js/containers/search/filters/naics/NAICSListContainer.jsx index c0511d5ead..e07135b27c 100644 --- a/src/js/containers/search/filters/naics/NAICSListContainer.jsx +++ b/src/js/containers/search/filters/naics/NAICSListContainer.jsx @@ -52,11 +52,9 @@ export class NAICSListContainer extends React.Component { const values = []; if (naics.length > 0) { naics.forEach((item) => { - const description = upperCase(item.naics_description); - values.push({ - title: item.naics, - subtitle: description, + title: `${item.naics} - ${item.naics_description}`, + subtitle: '', data: item }); }); diff --git a/src/js/containers/search/filters/psc/PSCListContainer.jsx b/src/js/containers/search/filters/psc/PSCListContainer.jsx index 218381e68d..de7a33dc64 100644 --- a/src/js/containers/search/filters/psc/PSCListContainer.jsx +++ b/src/js/containers/search/filters/psc/PSCListContainer.jsx @@ -54,7 +54,7 @@ export class PSCListContainer extends React.Component { psc.forEach((item) => { values.push({ title: item.product_or_service_code, - subtitle: 'PSC Code', + subtitle: '', data: item }); }); From 8076178d499222657337c5c3af57ad7c6267f656 Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Thu, 27 Jul 2017 17:24:41 -0400 Subject: [PATCH 64/97] Lint fix --- src/js/containers/search/filters/cfda/CFDAListContainer.jsx | 2 +- src/js/containers/search/filters/naics/NAICSListContainer.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index 7c30744716..afddee7a1c 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -6,7 +6,7 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { isEqual, upperCase, omit, differenceWith, slice } from 'lodash'; +import { isEqual, omit, differenceWith, slice } from 'lodash'; import { isCancel } from 'axios'; import { Search } from 'js-search'; import PropTypes from 'prop-types'; diff --git a/src/js/containers/search/filters/naics/NAICSListContainer.jsx b/src/js/containers/search/filters/naics/NAICSListContainer.jsx index e07135b27c..efd9a79f06 100644 --- a/src/js/containers/search/filters/naics/NAICSListContainer.jsx +++ b/src/js/containers/search/filters/naics/NAICSListContainer.jsx @@ -6,7 +6,7 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { isEqual, upperCase, omit, differenceWith, slice } from 'lodash'; +import { isEqual, omit, differenceWith, slice } from 'lodash'; import { isCancel } from 'axios'; import { Search } from 'js-search'; import PropTypes from 'prop-types'; From dd670bbaa3601c1764e274de8c16189dfddc23df Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 27 Jul 2017 18:06:34 -0400 Subject: [PATCH 65/97] Enable award type scopes in agency recipient visualization --- .../visualizations/recipient/ScopeList.jsx | 44 +++---- .../visualizations/RecipientContainer.jsx | 10 +- tests/containers/agency/agencyHelper.js | 15 +++ .../RecipientContainer-test.jsx | 116 ++++++++++-------- 4 files changed, 105 insertions(+), 80 deletions(-) diff --git a/src/js/components/agency/visualizations/recipient/ScopeList.jsx b/src/js/components/agency/visualizations/recipient/ScopeList.jsx index 3bccae3f64..69892d2f1a 100644 --- a/src/js/components/agency/visualizations/recipient/ScopeList.jsx +++ b/src/js/components/agency/visualizations/recipient/ScopeList.jsx @@ -6,8 +6,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import ComingSoonLabel from 'components/sharedComponents/ComingSoonLabel'; - import RankVisualizationScopeButton from 'components/search/visualizations/rank/RankVisualizationScopeButton'; @@ -30,50 +28,40 @@ export default class ScopeList extends React.Component { active={this.props.scope === 'all'} changeScope={this.props.changeScope} /> -
  • +
  • - + active={this.props.scope === 'contract'} + changeScope={this.props.changeScope} />
  • -
  • +
  • - + active={this.props.scope === 'grant'} + changeScope={this.props.changeScope} />
  • -
  • +
  • - + active={this.props.scope === 'direct payments'} + changeScope={this.props.changeScope} />
  • -
  • +
  • - + changeScope={this.props.changeScope} />
  • -
  • +
  • - + changeScope={this.props.changeScope} />
  • diff --git a/src/js/containers/agency/visualizations/RecipientContainer.jsx b/src/js/containers/agency/visualizations/RecipientContainer.jsx index a764127341..11a84fe290 100644 --- a/src/js/containers/agency/visualizations/RecipientContainer.jsx +++ b/src/js/containers/agency/visualizations/RecipientContainer.jsx @@ -70,12 +70,18 @@ export default class RecipientContainer extends React.PureComponent { error: false }); - this.request = AgencyHelper.fetchAwardRecipients({ + const params = { fiscal_year: fy, awarding_agency_id: id, limit: 10, page: pageNumber - }); + }; + + if (this.state.scope !== 'all') { + params.award_category = this.state.scope; + } + + this.request = AgencyHelper.fetchAwardRecipients(params); this.request.promise .then((res) => { diff --git a/tests/containers/agency/agencyHelper.js b/tests/containers/agency/agencyHelper.js index 4a5232ba9b..f66a3b64ec 100644 --- a/tests/containers/agency/agencyHelper.js +++ b/tests/containers/agency/agencyHelper.js @@ -1,6 +1,8 @@ import { mockObligatedAmounts, mockCgacCode, mockFiscalQuarter } from './visualizations/mocks/mockObligatedAmounts'; +import { mockRecipient } from './visualizations/mocks/mockRecipient'; + // Fetch Agency Obligated Amounts export const fetchAgencyObligatedAmounts = () => ( { @@ -42,3 +44,16 @@ export const fetchAgencyFiscalQuarter = () => ( cancel: jest.fn() } ); + +export const fetchAwardRecipients = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockRecipient + }); + }); + }), + cancel: jest.fn() + } +); diff --git a/tests/containers/agency/visualizations/RecipientContainer-test.jsx b/tests/containers/agency/visualizations/RecipientContainer-test.jsx index 591bb04716..23f0325e24 100644 --- a/tests/containers/agency/visualizations/RecipientContainer-test.jsx +++ b/tests/containers/agency/visualizations/RecipientContainer-test.jsx @@ -8,7 +8,6 @@ import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; import RecipientContainer from 'containers/agency/visualizations/RecipientContainer'; -import * as AgencyHelper from 'helpers/agencyHelper'; import { mockRecipient, parsedSeries } from './mocks/mockRecipient'; @@ -36,56 +35,20 @@ jest.mock('containers/glossary/GlossaryButtonWrapperContainer', () => jest.mock('containers/glossary/GlossaryContainer', () => jest.fn(() => null)); -const mockAgencyHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - AgencyHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; - -const unmockAgencyHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/accountHelper'); -}; +jest.mock('helpers/agencyHelper', () => require('../agencyHelper')); describe('RecipientContainer', () => { - it('should make an API call for the selected account on mount', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); - - mount( { + const container = mount(); - jest.runAllTicks(); + await container.instance().request.promise; expect(loadDataSpy.callCount).toEqual(1); loadDataSpy.reset(); - - unmockAgencyHelper(); }); it('should make a new API call when the inbound agency ID prop changes', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); - const container = mount(); @@ -97,18 +60,13 @@ describe('RecipientContainer', () => { id: '555' }); - jest.runAllTicks(); - // expect(loadDataSpy.callCount).toEqual(1); expect(loadDataMock).toHaveBeenCalledWith('555', inboundProps.activeFY, 1); loadDataSpy.reset(); - - unmockAgencyHelper(); }); describe('changePage', () => { it('should update the page number in state', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); const container = shallow(); @@ -122,7 +80,6 @@ describe('RecipientContainer', () => { expect(container.state().page).toEqual(2); }); it('should make an API call with the new page number', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); const container = shallow(); @@ -138,7 +95,6 @@ describe('RecipientContainer', () => { }); it('should not do anything if there are no more pages', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); const container = shallow(); @@ -158,20 +114,80 @@ describe('RecipientContainer', () => { describe('changeScope', () => { it('should update the state with the new scope', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); const container = shallow(); expect(container.state().scope).toEqual('all'); + container.instance().changeScope('contract'); + expect(container.state().scope).toEqual('contract'); + }); + + it('should trigger an API call', () => { + const container = shallow(); + + const loadDataMock = jest.fn(); + container.instance().loadData = loadDataMock; + container.instance().changeScope('contracts'); expect(container.state().scope).toEqual('contracts'); + expect(loadDataMock).toHaveBeenCalledTimes(1); + }); + }); + + describe('loadData', () => { + it('should not include a scope when the scope state is "all"', async () => { + const apiSpy = sinon.spy(require('helpers/agencyHelper'), 'fetchAwardRecipients'); + const container = shallow(); + + await container.instance().request.promise; + expect(apiSpy.callCount).toEqual(1); + + container.setState({ + scope: 'all' + }); + + container.instance().loadData(123, 2017, 1) +; + await container.instance().request.promise; + expect(apiSpy.callCount).toEqual(2); + + const spyCalls = apiSpy.getCalls(); + const args = spyCalls[1].args[0]; + expect(args.award_category).toBeUndefined(); + + apiSpy.restore(); + }); + + it('should include a scope when the scope state is not "all"', async () => { + const apiSpy = sinon.spy(require('helpers/agencyHelper'), 'fetchAwardRecipients'); + const container = shallow(); + + await container.instance().request.promise; + expect(apiSpy.callCount).toEqual(1); + + container.setState({ + scope: 'contract' + }); + + container.instance().loadData(123, 2017, 1) +; + await container.instance().request.promise; + expect(apiSpy.callCount).toEqual(2); + + const spyCalls = apiSpy.getCalls(); + const args = spyCalls[1].args[0]; + expect(args.award_category).toEqual('contract'); + + apiSpy.restore(); }); }); describe('parseData', () => { it('should parse the returned API response', () => { - mockAgencyHelper('fetchAwardRecipients', 'resolve', mockRecipient); const container = shallow(); From 94eca8048e2179c8cc3b4bc57ad7d48d43d26b51 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Fri, 28 Jul 2017 16:08:21 -0400 Subject: [PATCH 66/97] Updated recipient autocomplete and tests to handle parent recipients --- .../filters/recipient/SelectedRecipients.jsx | 2 +- .../filterGroups/RecipientFilterGroup.jsx | 4 +- .../recipient/RecipientNameDUNSContainer.jsx | 33 ++-- .../filters/recipientFilterFunctions.js | 2 +- .../RecipientNameDUNSContainer-test.jsx | 82 +++++++++- .../filters/recipientFilter/mockRecipients.js | 93 ++++++----- .../redux/reducers/search/mock/mockFilters.js | 148 +----------------- .../search/searchFiltersReducer-test.js | 2 +- 8 files changed, 165 insertions(+), 201 deletions(-) diff --git a/src/js/components/search/filters/recipient/SelectedRecipients.jsx b/src/js/components/search/filters/recipient/SelectedRecipients.jsx index 797fc65bc6..753cc4f7c7 100644 --- a/src/js/components/search/filters/recipient/SelectedRecipients.jsx +++ b/src/js/components/search/filters/recipient/SelectedRecipients.jsx @@ -20,7 +20,7 @@ export default class SelectedRecipients extends React.Component { const recipient = entry[1]; const value = (); shownRecipients.push(value); diff --git a/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx index d8f8fa14f3..78b0883c50 100644 --- a/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx +++ b/src/js/components/search/topFilterBar/filterGroups/RecipientFilterGroup.jsx @@ -42,8 +42,8 @@ export default class RecipientFilterGroup extends React.Component { recipients.forEach((value) => { const tag = { - value: `${value.recipient_unique_id}`, - title: `${value.recipient_name} | ${value.recipient_unique_id}`, + value: `${value.legal_entity_id}`, + title: `${value.recipient_name} | ${value.duns}`, isSpecial: false, removeFilter: this.removeFilter }; diff --git a/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx b/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx index 4828f179dc..d825e4020d 100644 --- a/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx +++ b/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx @@ -7,7 +7,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { isEqual, differenceWith, slice } from 'lodash'; +import { isEqual, concat, differenceWith, slice } from 'lodash'; import { isCancel } from 'axios'; import { Search } from 'js-search'; @@ -53,10 +53,19 @@ export class RecipientNameDUNSContainer extends React.Component { const values = []; if (recipients.length > 0) { recipients.forEach((item) => { + let subtitle = `DUNS: ${item.recipient_unique_id}`; + let duns = item.recipient_unique_id; + if (item.parent_recipient_unique_id) { + subtitle = `Parent DUNS: ${item.parent_recipient_unique_id}`; + duns = item.parent_recipient_unique_id; + } + values.push({ + subtitle, title: item.recipient_name, - subtitle: `DUNS: ${item.recipient_unique_id}`, - data: item + data: Object.assign({}, item, { + duns + }) }); }); } @@ -91,7 +100,11 @@ export class RecipientNameDUNSContainer extends React.Component { this.recipientSearchRequest.promise .then((res) => { - this.performSecondarySearch(res.data.results); + const parentResults = this.performSecondarySearch( + res.data.results.parent_recipient[0], 'parent_recipient_unique_id'); + const normalResults = this.performSecondarySearch( + res.data.results.recipient[0], 'recipient_unique_id'); + this.parseResults(parentResults, normalResults); }) .catch((err) => { if (!isCancel(err)) { @@ -107,12 +120,12 @@ export class RecipientNameDUNSContainer extends React.Component { } } - performSecondarySearch(data) { + performSecondarySearch(data, dunsKey) { // search within the returned data // create a search index with the API response records const search = new Search('legal_entity_id'); search.addIndex('recipient_name'); - search.addIndex('recipient_unique_id'); + search.addIndex(dunsKey); // add the API response as the data source to search within search.addDocuments(data); @@ -122,11 +135,13 @@ export class RecipientNameDUNSContainer extends React.Component { // combine the two arrays and limit it to 10 const improvedResults = slice(results, 0, 10); - - this.parseResults(improvedResults); + return improvedResults; } - parseResults(data) { + parseResults(parent, normal) { + // combine the two arrays + const data = slice(concat(parent, normal), 0, 10); + let autocompleteData = []; const selectedRecipients = this.props.selectedRecipients.toArray(); // Filter out any selectedRecipients that may be in the result set diff --git a/src/js/redux/reducers/search/filters/recipientFilterFunctions.js b/src/js/redux/reducers/search/filters/recipientFilterFunctions.js index 83b47def58..82910a8f46 100644 --- a/src/js/redux/reducers/search/filters/recipientFilterFunctions.js +++ b/src/js/redux/reducers/search/filters/recipientFilterFunctions.js @@ -8,7 +8,7 @@ import { Set } from 'immutable'; export const updateSelectedRecipients = (state, value) => { let updatedSet = state; - const agencyIdentifier = `${value.recipient_unique_id}`; + const agencyIdentifier = `${value.legal_entity_id}`; // force it to a string if (updatedSet.has(agencyIdentifier)) { updatedSet = updatedSet.delete(agencyIdentifier); diff --git a/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx b/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx index 1897c99d78..ecd761cf2b 100644 --- a/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx +++ b/tests/containers/search/filters/recipientFilter/RecipientNameDUNSContainer-test.jsx @@ -4,14 +4,17 @@ */ import React from 'react'; -import { mount } from 'enzyme'; +import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; import { OrderedMap } from 'immutable'; import { RecipientNameDUNSContainer } from 'containers/search/filters/recipient/RecipientNameDUNSContainer'; +import { mockAutocompleteRedux, expectedAutocomplete } from './mockRecipients'; + const setup = (props) => mount(); +const setupShallow = (props) => shallow(); jest.mock('helpers/searchHelper', () => require('../searchHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -202,4 +205,81 @@ describe('RecipientNameDUNSContainer', () => { parseAutocompleteRecipientsSpy.reset(); }); }); + + describe('parseAutocompleteRecipients', () => { + it('should display the parent DUNS when available', () => { + const container = setupShallow({ + setAutocompleteRecipients: jest.fn(), + toggleRecipient: jest.fn(), + selectedRecipients: new OrderedMap(), + autocompleteRecipients: [] + }); + + container.instance().parseAutocompleteRecipients([mockAutocompleteRedux[0]]); + + expect(container.state().autocompleteRecipients[0]).toEqual(expectedAutocomplete[0]); + }); + it('should display the recipient DUNS when there is no parent DUNS', () => { + const container = setupShallow({ + setAutocompleteRecipients: jest.fn(), + toggleRecipient: jest.fn(), + selectedRecipients: new OrderedMap(), + autocompleteRecipients: [] + }); + + container.instance().parseAutocompleteRecipients([mockAutocompleteRedux[1]]); + + expect(container.state().autocompleteRecipients[0]).toEqual(expectedAutocomplete[1]); + }); + }); + + describe('parseResults', () => { + it('should put parent recipient results at the front of the array', () => { + const mockRedux = jest.fn(); + + const container = setupShallow({ + setAutocompleteRecipients: mockRedux, + toggleRecipient: jest.fn(), + selectedRecipients: new OrderedMap(), + autocompleteRecipients: [] + }); + + const parent = [1, 2]; + const normal = [3, 4]; + + container.instance().parseResults(parent, normal); + + expect(mockRedux).toHaveBeenCalledTimes(1); + expect(mockRedux.mock.calls[0][0]).toEqual([1, 2, 3, 4]); + }); + it('should remove already selected recipients from the array', () => { + const mockRedux = jest.fn(); + + const container = setupShallow({ + setAutocompleteRecipients: mockRedux, + toggleRecipient: jest.fn(), + selectedRecipients: new OrderedMap({ + 1111: { + legal_entity_id: 1111, + recipient_name: "MEGA CONGLOMERATE CORP", + parent_recipient_unique_id: "001122334" + } + }), + autocompleteRecipients: [] + }); + + const parent = [ + { + legal_entity_id: 1111, + recipient_name: "MEGA CONGLOMERATE CORP", + parent_recipient_unique_id: "001122334" + } + ]; + + container.instance().parseResults(parent, []); + + expect(mockRedux).toHaveBeenCalledTimes(1); + expect(mockRedux.mock.calls[0][0]).toEqual([]); + }); + }); }); diff --git a/tests/containers/search/filters/recipientFilter/mockRecipients.js b/tests/containers/search/filters/recipientFilter/mockRecipients.js index b1c0524792..1955d97a18 100644 --- a/tests/containers/search/filters/recipientFilter/mockRecipients.js +++ b/tests/containers/search/filters/recipientFilter/mockRecipients.js @@ -6,45 +6,56 @@ export const mockRecipientLocation = [{ }]; export const mockRecipientDUNS = { - results: [{ - legal_entity_id: 1256, - recipient_name: "BOOZ ALLEN HAMILTON INC.", - recipient_unique_id: "077368509" - }, { - legal_entity_id: 35, - recipient_name: "BOOZ ALLEN HAMILTON INC", - recipient_unique_id: "006928857" - }, { - legal_entity_id: 3961, - recipient_name: "BOOZ ALLEN HAMILTON INC.", - recipient_unique_id: "004679015" - }, { - legal_entity_id: 2511, - recipient_name: "ALLAN BAKER, INC.", - recipient_unique_id: "147795132" - }, { - legal_entity_id: 3939, - recipient_name: "ALL BUSINESS MACHINES, INC.", - recipient_unique_id: "104178756" - }, { - legal_entity_id: 6609, - recipient_name: "BOVA, JEFFREY ALAN", - recipient_unique_id: "078440988" - }, { - legal_entity_id: 8482, - recipient_name: "FOR ALL SEASONS INC", - recipient_unique_id: "179268370" - }, { - legal_entity_id: 1190, - recipient_name: "ALLSTEEL INC.", - recipient_unique_id: "120316711" - }, { - legal_entity_id: 8593, - recipient_name: "BOONE, TOWN OF", - recipient_unique_id: "021395942" - }, { - legal_entity_id: 8346, - recipient_name: "ALLEN, CITY OF", - recipient_unique_id: "788275956" - }] + results: { + parent_recipient: [ + { + legal_entity_id: 1111, + recipient_name: "MEGA CONGLOMERATE CORP", + parent_recipient_unique_id: "001122334" + } + ], + recipient: [ + { + legal_entity_id: 2222, + recipient_name: "MEGA CONGLOMERATE CORP PIZZA DIVISION", + recipient_unique_id: "001122335" + } + ] + } }; + +export const mockAutocompleteRedux = [ + { + legal_entity_id: 1111, + recipient_name: "MEGA CONGLOMERATE CORP", + parent_recipient_unique_id: "001122334" + }, + { + legal_entity_id: 2222, + recipient_name: "MEGA CONGLOMERATE CORP PIZZA DIVISION", + recipient_unique_id: "001122335" + } +]; + +export const expectedAutocomplete = [ + { + title: 'MEGA CONGLOMERATE CORP', + subtitle: 'Parent DUNS: 001122334', + data: { + legal_entity_id: 1111, + recipient_name: "MEGA CONGLOMERATE CORP", + parent_recipient_unique_id: "001122334", + duns: "001122334" + } + }, + { + title: 'MEGA CONGLOMERATE CORP PIZZA DIVISION', + subtitle: 'DUNS: 001122335', + data: { + legal_entity_id: 2222, + recipient_name: "MEGA CONGLOMERATE CORP PIZZA DIVISION", + recipient_unique_id: "001122335", + duns: "001122335" + } + } +]; diff --git a/tests/redux/reducers/search/mock/mockFilters.js b/tests/redux/reducers/search/mock/mockFilters.js index d4456c8a7b..9c898f724e 100644 --- a/tests/redux/reducers/search/mock/mockFilters.js +++ b/tests/redux/reducers/search/mock/mockFilters.js @@ -1,149 +1,7 @@ export const mockRecipient = { - legal_entity_id: 973, - data_source: null, - parent_recipient_unique_id: "964725688", - recipient_name: "BOOZ ALLEN HAMILTON INC.", - vendor_doing_as_business_name: null, - vendor_phone_number: "7033770195", - vendor_fax_number: "7039023200", - business_types: "UN", - business_types_description: "Unknown Business Type", - recipient_unique_id: "006928857", - limited_liability_corporation: "f", - sole_proprietorship: "f", - partnership_or_limited_liability_partnership: "f", - subchapter_scorporation: "f", - foundation: "f", - for_profit_organization: "t", - nonprofit_organization: "f", - corporate_entity_tax_exempt: "f", - corporate_entity_not_tax_exempt: "t", - other_not_for_profit_organization: "f", - sam_exception: null, - city_local_government: "f", - county_local_government: "f", - inter_municipal_local_government: "f", - local_government_owned: "f", - municipality_local_government: "f", - school_district_local_government: "f", - township_local_government: "f", - us_state_government: null, - us_federal_government: "f", - federal_agency: "f", - federally_funded_research_and_development_corp: "f", - us_tribal_government: "f", - foreign_government: "f", - community_developed_corporation_owned_firm: "f", - labor_surplus_area_firm: "f", - small_agricultural_cooperative: "f", - international_organization: "f", - us_government_entity: null, - emerging_small_business: null, - c8a_program_participant: "f", - sba_certified_8a_joint_venture: null, - dot_certified_disadvantage: "f", - self_certified_small_disadvantaged_business: null, - historically_underutilized_business_zone: "f", - small_disadvantaged_business: null, - the_ability_one_program: null, - historically_black_college: "f", - c1862_land_grant_college: "f", - c1890_land_grant_college: "f", - c1994_land_grant_college: "f", - minority_institution: "f", - private_university_or_college: "f", - school_of_forestry: "f", - state_controlled_institution_of_higher_learning: "f", - tribal_college: "f", - veterinary_college: "f", - educational_institution: "f", - alaskan_native_servicing_institution: "f", - community_development_corporation: "f", - native_hawaiian_servicing_institution: "f", - domestic_shelter: "f", - manufacturer_of_goods: "f", - hospital_flag: "f", - veterinary_hospital: "f", - hispanic_servicing_institution: "f", - woman_owned_business: "f", - minority_owned_business: "f", - women_owned_small_business: null, - economically_disadvantaged_women_owned_small_business: null, - joint_venture_women_owned_small_business: null, - joint_venture_economic_disadvantaged_women_owned_small_bus: null, - veteran_owned_business: "f", - service_disabled_veteran_owned_business: null, - contracts: null, - grants: null, - receives_contracts_and_grants: null, - airport_authority: "f", - council_of_governments: "f", - housing_authorities_public_tribal: "f", - interstate_entity: "f", - planning_commission: "f", - port_authority: "f", - transit_authority: "f", - foreign_owned_and_located: "f", - american_indian_owned_business: "f", - alaskan_native_owned_corporation_or_firm: "f", - indian_tribe_federally_recognized: "f", - native_hawaiian_owned_business: "f", - tribally_owned_business: "f", - asian_pacific_american_owned_business: "f", - black_american_owned_business: "f", - hispanic_american_owned_business: "f", - native_american_owned_business: "f", - subcontinent_asian_asian_indian_american_owned_business: "f", - other_minority_owned_business: "f", - us_local_government: "f", - undefinitized_action: null, - domestic_or_foreign_entity: null, - division_name: null, - division_number: null, - last_modified_date: null, - certified_date: null, - reporting_period_start: null, - reporting_period_end: null, - create_date: "2017-02-15T20:06:43.024083Z", - update_date: "2017-02-15T20:06:43.024108Z", - city_township_government: null, - special_district_government: null, - small_business: null, - individual: null, - location: { - location_id: 12619, - data_source: null, - country_name: "UNITED STATES", - state_code: "VA", - state_name: null, - state_description: null, - city_name: "McLean", - city_code: "48376", - county_name: "Fairfax", - county_code: "59", - address_line1: "8283 GREENSBORO DR", - address_line2: "", - address_line3: "", - foreign_location_description: null, - zip4: null, - zip_4a: null, - congressional_code: "11", - performance_code: null, - zip_last4: "3830", - zip5: "22102", - foreign_postal_code: null, - foreign_province: null, - foreign_city_name: null, - reporting_period_start: null, - reporting_period_end: null, - last_modified_date: null, - certified_date: null, - create_date: "2017-02-15T20:32:31.411437Z", - update_date: "2017-02-15T20:32:31.411470Z", - place_of_performance_flag: false, - recipient_flag: false, - location_country_code: "USA" - } + legal_entity_id: 2222, + recipient_name: "MEGA CONGLOMERATE CORP PIZZA DIVISION", + recipient_unique_id: "001122335" }; export const mockAgency = { diff --git a/tests/redux/reducers/search/searchFiltersReducer-test.js b/tests/redux/reducers/search/searchFiltersReducer-test.js index 6de547f2de..c67b7a740d 100644 --- a/tests/redux/reducers/search/searchFiltersReducer-test.js +++ b/tests/redux/reducers/search/searchFiltersReducer-test.js @@ -351,7 +351,7 @@ describe('searchFiltersReducer', () => { recipient: mockRecipient }; - const recipient = "006928857"; + const recipient = '2222'; const expectedRecipient = mockRecipient; From 65e585bfea2fdb557e0433239cd981d2c9e76bc0 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Fri, 28 Jul 2017 16:20:45 -0400 Subject: [PATCH 67/97] Fix percentages --- src/js/containers/agencyLanding/AgencyLandingContainer.jsx | 4 +++- .../containers/agencyLanding/AgencyLandingContainer-test.jsx | 4 ++-- tests/containers/agencyLanding/mockToptierAgencies.js | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 6c7c7a0a4f..7cf26b5757 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -173,8 +173,10 @@ export class AgencyLandingContainer extends React.Component { const formattedCurrency = MoneyFormatter.formatMoneyWithPrecision(item.budget_authority_amount, 0); + // Convert from decimal value to percentage + const percentage = item.percentage_of_total_budget_authority * 100; // Round percentage to 2 decimal places - let percent = Math.round(parseFloat(item.percentage_of_total_budget_authority) * 100) / 100; + let percent = Math.round(parseFloat(percentage) * 100) / 100; if (percent === 0.00) { percent = 'Less than 0.01%'; diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index 5032560d89..adc27d2b62 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -114,13 +114,13 @@ describe('AgencyLandingContainer', () => { agency_id: 1, agency_name: Test 1, budget_authority_amount: "$1,234,567", - percentage_of_total_budget_authority: "0.01%" + percentage_of_total_budget_authority: "1.21%" }), new Agency({ agency_id: 2, agency_name: Test 2, budget_authority_amount: "$2,345,678", - percentage_of_total_budget_authority: "0.02%" + percentage_of_total_budget_authority: "2.32%" }) ]); delete expected._jsid; diff --git a/tests/containers/agencyLanding/mockToptierAgencies.js b/tests/containers/agencyLanding/mockToptierAgencies.js index 4ba8707920..98731e439b 100644 --- a/tests/containers/agencyLanding/mockToptierAgencies.js +++ b/tests/containers/agencyLanding/mockToptierAgencies.js @@ -7,13 +7,13 @@ export const mockData = { agency_id: 1, agency_name: 'Test 1', budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.012' + percentage_of_total_budget_authority: '0.01211' }, { agency_id: 2, agency_name: 'Test 2', budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.023' + percentage_of_total_budget_authority: '0.02322' } ] }; From c096c84c472ff2f01b94b37249c81a7694f9d541 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Sat, 29 Jul 2017 16:46:12 -0400 Subject: [PATCH 68/97] Fix tooltip positioning, fix IE header issue --- src/_scss/mixins/moreOptionsBtn.scss | 1 + .../visualizations/time/TimeTooltip.jsx | 49 ++++++++++++++++--- .../visualizations/time/TimeVisualization.jsx | 4 +- .../time/chart/BarChartStacked.jsx | 6 --- .../chart/{OutlayLine.js => OutlayLine.jsx} | 1 - .../time/chart/StackedBarGroup.jsx | 4 +- 6 files changed, 45 insertions(+), 20 deletions(-) rename src/js/components/account/visualizations/time/chart/{OutlayLine.js => OutlayLine.jsx} (97%) diff --git a/src/_scss/mixins/moreOptionsBtn.scss b/src/_scss/mixins/moreOptionsBtn.scss index 937e43f7e9..44b45e2c63 100644 --- a/src/_scss/mixins/moreOptionsBtn.scss +++ b/src/_scss/mixins/moreOptionsBtn.scss @@ -3,6 +3,7 @@ float: right; fill: $baseColor; height: rem(30); + width: rem(50); border: rem(1) solid rgba($baseColor, .6); padding: 0 rem(10); } diff --git a/src/js/components/account/visualizations/time/TimeTooltip.jsx b/src/js/components/account/visualizations/time/TimeTooltip.jsx index 782f1739a5..cf7b1f3512 100644 --- a/src/js/components/account/visualizations/time/TimeTooltip.jsx +++ b/src/js/components/account/visualizations/time/TimeTooltip.jsx @@ -11,26 +11,59 @@ import TooltipItem from './TooltipItem'; const propTypes = { xValue: PropTypes.string, values: PropTypes.array, - position: PropTypes.object, - width: PropTypes.number, - height: PropTypes.number + position: PropTypes.object }; export default class TimeTooltip extends React.Component { + constructor(props) { + super(props); + + this.state = { + windowWidth: 0, + tooltipWidth: 0, + xOffset: 0 + }; + + this.measureDOM = this.measureDOM.bind(this); + } + componentDidMount() { - this.positionTooltip(); + this.measureDOM(); + window.addEventListener('resize', this.measureDOM); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.measureDOM); + } + + measureDOM() { + // measure the window width + const windowWidth = window.innerWidth; + const tooltipWidth = this.div.offsetWidth; + // measure where on the screen the tooltip's 0 x position is + const xOffset = this.div.getBoundingClientRect().left; + + // save the measurements before updating the tooltip, this prevents layout thrashing + this.setState({ + windowWidth, + tooltipWidth, + xOffset + }, this.positionTooltip); } positionTooltip() { // we need to wait for the tooltip to render before we can full position it due to its // dynamic width - const tooltipWidth = this.div.offsetWidth; - const windowWidth = window.innerWidth; + const tooltipWidth = this.state.tooltipWidth; + // determine how far from the right edge of the window we are + const distanceFromRight = this.state.windowWidth - + (this.state.xOffset + this.props.position.x + tooltipWidth); // determine the tooltip direction let direction = 'left'; - // allow 20px padding - if (tooltipWidth + this.props.position.x >= windowWidth - 20) { + // if we are less than 20px from the right edge, the arrow should point right (bc the + // tooltip will be on the left of the bar) + if (distanceFromRight <= 20) { direction = 'right'; } diff --git a/src/js/components/account/visualizations/time/TimeVisualization.jsx b/src/js/components/account/visualizations/time/TimeVisualization.jsx index 3284542d13..880d2636fc 100644 --- a/src/js/components/account/visualizations/time/TimeVisualization.jsx +++ b/src/js/components/account/visualizations/time/TimeVisualization.jsx @@ -140,9 +140,7 @@ export default class TimeVisualization extends React.Component { let tooltip = null; if (this.state.showTooltip) { tooltip = (); + {...this.state.tooltipData} />); } return ( diff --git a/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx b/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx index 7ea16e3c5e..18fe5af60b 100644 --- a/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx +++ b/src/js/components/account/visualizations/time/chart/BarChartStacked.jsx @@ -62,7 +62,6 @@ export default class BarChartStacked extends React.Component { } buildVirtualChart(props) { - const startTime = window.performance.now(); const values = { width: props.width, height: props.height, @@ -112,11 +111,6 @@ export default class BarChartStacked extends React.Component { body }; - const endTime = window.performance.now(); - console.log(`calc ${endTime - startTime}ms`); - - // console.log(JSON.stringify(chart) === JSON.stringify(this.state.virtualChart)); - this.setState({ virtualChart: chart, chartReady: true diff --git a/src/js/components/account/visualizations/time/chart/OutlayLine.js b/src/js/components/account/visualizations/time/chart/OutlayLine.jsx similarity index 97% rename from src/js/components/account/visualizations/time/chart/OutlayLine.js rename to src/js/components/account/visualizations/time/chart/OutlayLine.jsx index c8b994d1d6..d049f31939 100644 --- a/src/js/components/account/visualizations/time/chart/OutlayLine.js +++ b/src/js/components/account/visualizations/time/chart/OutlayLine.jsx @@ -15,7 +15,6 @@ const propTypes = { x: PropTypes.number, y: PropTypes.number, width: PropTypes.number, - height: PropTypes.number, color: PropTypes.string }; diff --git a/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx b/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx index 8aeca205df..a814568f11 100644 --- a/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx +++ b/src/js/components/account/visualizations/time/chart/StackedBarGroup.jsx @@ -45,12 +45,12 @@ export default class StackedBarGroup extends React.Component { if (item.type === 'bar') { return (); + key={`${item.name}-${item.xValue}`} />); } return ( ); + key={`${item.name}-${item.xValue}`} />); }); return ( From ae65bcb52e58271fd941cfe56a74c468a8bbb093 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Sat, 29 Jul 2017 17:30:55 -0400 Subject: [PATCH 69/97] Update unit tests --- .../AccountTimeVisualizationContainer.jsx | 4 +- tests/containers/account/accountHelper.js | 14 ++ tests/containers/account/mockAccount.js | 146 +++++++++++++++ ...AccountTimeVisualizationContainer-test.jsx | 167 ++++-------------- 4 files changed, 201 insertions(+), 130 deletions(-) diff --git a/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx b/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx index b94479b3b6..1829dc79af 100644 --- a/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx +++ b/src/js/containers/account/visualizations/AccountTimeVisualizationContainer.jsx @@ -30,7 +30,7 @@ const propTypes = { }; // create an Immuatable Record object to guarantee the existance of required visualization fields -const VisData = Record({ +export const VisData = Record({ xSeries: [], ySeries: [], allY: [], @@ -319,7 +319,7 @@ export class AccountTimeVisualizationSectionContainer extends React.PureComponen bottom: yData[quarterYear].obligated, top: yData[quarterYear].unobligated + yData[quarterYear].obligated, value: yData[quarterYear].unobligated, - description: 'Unobligated balance' + description: 'Unobligated Balance' }, outlay: { bottom: yData[quarterYear].outlay, diff --git a/tests/containers/account/accountHelper.js b/tests/containers/account/accountHelper.js index fa3de8a068..94116cccdc 100644 --- a/tests/containers/account/accountHelper.js +++ b/tests/containers/account/accountHelper.js @@ -42,3 +42,17 @@ export const fetchTasBalanceTotals = () => ( cancel: jest.fn() } ); + +export const fetchTasCategoryTotals = () => ( + { + promise: new Promise((resolve) => { + process.nextTick(() => { + resolve({ + data: mockBalances.outlay + }); + }); + }), + cancel: jest.fn() + } +); + diff --git a/tests/containers/account/mockAccount.js b/tests/containers/account/mockAccount.js index 0c5efe0877..f972c9a668 100644 --- a/tests/containers/account/mockAccount.js +++ b/tests/containers/account/mockAccount.js @@ -605,3 +605,149 @@ export const mockTabCount = { type: "11" }] }; + +export const parsedYearYSeries = { + obligated: { + bottom: 0, + top: 2696684.86, + value: 2696684.86, + description: 'Obligations Incurred' + }, + unobligated: { + bottom: 2696684.86, + top: 198707976.61 + 2696684.86, + value: 198707976.61, + description: 'Unobligated Balance' + }, + outlay: { + bottom: -5505246.42, + top: -5505246.42, + value: -5505246.42, + description: 'Outlay' + } +}; + +export const parsedYearYSeriesFiltered = { + obligatedFiltered: { + bottom: 0, + top: 2696684.86, + value: 2696684.86, + description: 'Obligations Incurred (Filtered)' + }, + obligatedOther: { + bottom: 2696684.86, + top: (201404661.47 - 198707976.61 - 2696684.86) + 2696684.86, + value: (201404661.47 - 198707976.61 - 2696684.86), + description: 'Obligations Incurred (Other)' + }, + unobligated: { + bottom: (201404661.47 - 198707976.61), + top: 201404661.47, + value: 198707976.61, + description: 'Unobligated Balance' + }, + outlay: { + bottom: -5505246.42, + top: -5505246.42, + value: -5505246.42, + description: 'Outlay' + } +}; + +export const parsedQuarterYSeries = [ + { + obligated: { + bottom: 0, + top: 2696684.86, + value: 2696684.86, + description: 'Obligations Incurred' + }, + unobligated: { + bottom: 2696684.86, + top: 198707976.61 + 2696684.86, + value: 198707976.61, + description: 'Unobligated Balance' + }, + outlay: { + bottom: -5505246.42, + top: -5505246.42, + value: -5505246.42, + description: 'Outlay' + } + }, + { + obligated: { + bottom: 0, + top: 3851752.00, + value: 3851752.00, + description: 'Obligations Incurred' + }, + unobligated: { + bottom: 3851752.00, + top: 5851779752.00 + 3851752.00, + value: 5851779752.00, + description: 'Unobligated Balance' + }, + outlay: { + bottom: -4413237.11, + top: -4413237.11, + value: -4413237.11, + description: 'Outlay' + } + } +]; + +export const parsedQuarterYSeriesFiltered = [ + { + obligatedFiltered: { + bottom: 0, + top: 2696684.86, + value: 2696684.86, + description: 'Obligations Incurred (Filtered)' + }, + obligatedOther: { + bottom: 2696684.86, + top: (201404661.47 - 198707976.61 - 2696684.86) + 2696684.86, + value: (201404661.47 - 198707976.61 - 2696684.86), + description: 'Obligations Incurred (Other)' + }, + unobligated: { + bottom: (201404661.47 - 198707976.61), + top: 201404661.47, + value: 198707976.61, + description: 'Unobligated Balance' + }, + outlay: { + bottom: -5505246.42, + top: -5505246.42, + value: -5505246.42, + description: 'Outlay' + } + }, + { + obligatedFiltered: { + bottom: 0, + top: 3851752.00, + value: 3851752.00, + description: 'Obligations Incurred (Filtered)' + }, + obligatedOther: { + bottom: 3851752.00, + top: (101905442.35 - 5851779752.00 - 3851752) + 3851752, + value: (101905442.35 - 5851779752.00 - 3851752), + description: 'Obligations Incurred (Other)' + }, + unobligated: { + bottom: (101905442.35 - 5851779752.00), + top: 101905442.35, + value: 5851779752.00, + description: 'Unobligated Balance' + }, + outlay: { + bottom: -4413237.11, + top: -4413237.11, + value: -4413237.11, + description: 'Outlay' + } + } +]; diff --git a/tests/containers/account/visualizations/AccountTimeVisualizationContainer-test.jsx b/tests/containers/account/visualizations/AccountTimeVisualizationContainer-test.jsx index 08cd4c199e..064d2cd4fa 100644 --- a/tests/containers/account/visualizations/AccountTimeVisualizationContainer-test.jsx +++ b/tests/containers/account/visualizations/AccountTimeVisualizationContainer-test.jsx @@ -7,80 +7,43 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; - import { AccountTimeVisualizationSectionContainer } from 'containers/account/visualizations/AccountTimeVisualizationContainer'; -import * as AccountHelper from 'helpers/accountHelper'; import { mockBalances, mockReduxAccount, mockQuarters, mockFilteredObligated, mockFilteredObligatedQuarters, - mockReduxAccountFiltered, mockReduxAccountQuarters, mockReduxAccountQuartersFiltered} + parsedYearYSeries, parsedQuarterYSeries, parsedYearYSeriesFiltered, parsedQuarterYSeriesFiltered } from '../mockAccount'; import { defaultFilters } from '../defaultFilters'; -// force Jest to use native Node promises -// see: https://facebook.github.io/jest/docs/troubleshooting.html#unresolved-promises -global.Promise = require.requireActual('promise'); - const fetchDataSpy = sinon.spy(AccountTimeVisualizationSectionContainer.prototype, 'fetchData'); // mock the child component by replacing it with a function that returns a null element jest.mock('components/account/visualizations/time/AccountTimeVisualizationSection', () => jest.fn(() => null)); -const mockAccountHelper = (functionName, event, expectedResponse) => { - jest.useFakeTimers(); - // override the specified function - AccountHelper[functionName] = jest.fn(() => { - // Axios normally returns a promise, replicate this, but return the expected result - const networkCall = new Promise((resolve, reject) => { - process.nextTick(() => { - if (event === 'resolve') { - resolve({ - data: expectedResponse - }); - } - else { - reject({ - data: expectedResponse - }); - } - }); - }); - - return { - promise: networkCall, - cancel: jest.fn() - }; - }); -}; +jest.mock('helpers/accountHelper', () => require('../accountHelper')); -const unmockAccountHelper = () => { - jest.useRealTimers(); - jest.unmock('helpers/accountHelper'); -}; describe('AccountTimeVisualizationSectionContainer', () => { - it('should load data on mount', () => { - mockAccountHelper('fetchTasBalanceTotals', 'resolve', mockBalances.outlay); - - mount( { + const container = mount(); - jest.runAllTicks(); + const promises = container.instance().balanceRequests.map((request) => request.promise); + await Promise.all(promises); expect(fetchDataSpy.callCount).toEqual(1); fetchDataSpy.reset(); }); - it('should reload data when the filters change', () => { - mockAccountHelper('fetchTasBalanceTotals', 'resolve', mockBalances.outlay); - + it('should reload data when the filters change', async () => { const container = mount(); - jest.runAllTicks(); + const promises = container.instance().balanceRequests.map((request) => request.promise); + await Promise.all(promises); expect(fetchDataSpy.callCount).toEqual(1); @@ -90,7 +53,8 @@ describe('AccountTimeVisualizationSectionContainer', () => { }) }); - jest.runAllTicks(); + const morePromises = container.instance().balanceRequests.map((request) => request.promise); + await Promise.all(morePromises); expect(fetchDataSpy.callCount).toEqual(2); fetchDataSpy.reset(); @@ -135,22 +99,17 @@ describe('AccountTimeVisualizationSectionContainer', () => { const expectedState = { allY: [2696684.86, -5505246.42, 201404661.47, 198707976.61], - groups: ["2016"], - loading: false, - visualizationPeriod: "year", - hasFilteredObligated: false, - xSeries: [["2016"]], + xSeries: ["2016"], ySeries: [ - [{ - budgetAuthority: parseFloat(mockReduxAccount.totals.budgetAuthority['2016']), - obligated: parseFloat(mockReduxAccount.totals.obligated['2016']), - outlay: parseFloat(mockReduxAccount.totals.outlay['2016']), - unobligated: parseFloat(mockReduxAccount.totals.unobligated['2016']) - }] + parsedYearYSeries ] }; - expect(container.state()).toEqual(expectedState); + // don't compare the stacks + const containerState = container.state().data.toJS(); + delete containerState.stacks; + + expect(containerState).toEqual(expectedState); }); }); @@ -198,28 +157,15 @@ describe('AccountTimeVisualizationSectionContainer', () => { const expectedState = { allY: [2696684.86, -5505246.42, 201404661.47, 198707976.61, 3851752, -4413237.11, 101905442.35, 5851779752], - groups: ["2016 Q1", "2016 Q2"], - hasFilteredObligated: false, - loading: false, - visualizationPeriod: "quarter", - xSeries: [["2016 Q1"], ["2016 Q2"]], - ySeries: [ - [{ - budgetAuthority: parseFloat(mockReduxAccountQuarters.totals.budgetAuthority['2016 Q1']), - obligated: parseFloat(mockReduxAccountQuarters.totals.obligated['2016 Q1']), - outlay: parseFloat(mockReduxAccountQuarters.totals.outlay['2016 Q1']), - unobligated: parseFloat(mockReduxAccountQuarters.totals.unobligated['2016 Q1']) - }], - [{ - budgetAuthority: parseFloat(mockReduxAccountQuarters.totals.budgetAuthority['2016 Q2']), - obligated: parseFloat(mockReduxAccountQuarters.totals.obligated['2016 Q2']), - outlay: parseFloat(mockReduxAccountQuarters.totals.outlay['2016 Q2']), - unobligated: parseFloat(mockReduxAccountQuarters.totals.unobligated['2016 Q2']) - }] - ] + xSeries: ["2016 Q1", "2016 Q2"], + ySeries: parsedQuarterYSeries }; - expect(container.state()).toEqual(expectedState); + // don't compare the stacks + const containerState = container.state().data.toJS(); + delete containerState.stacks; + + expect(containerState).toEqual(expectedState); }); }); @@ -263,31 +209,20 @@ describe('AccountTimeVisualizationSectionContainer', () => { } ]); - const budgetAuthority16 = parseFloat(mockReduxAccountFiltered.totals.budgetAuthority['2016']); - const obligatedFiltered16 = parseFloat(mockReduxAccountFiltered.totals.obligatedFiltered['2016']); - const unobligated16 = parseFloat(mockReduxAccountFiltered.totals.unobligated['2016']); - const expectedState = { allY: [2696684.86, -5505246.42, 201404661.47, 198707976.61], - groups: ["2016"], - hasFilteredObligated: true, - loading: false, - visualizationPeriod: "year", - xSeries: [["2016"]], + xSeries: ["2016"], ySeries: [ - [{ - budgetAuthority: budgetAuthority16, - obligatedFiltered: obligatedFiltered16, - outlay: parseFloat(mockReduxAccountFiltered.totals.outlay['2016']), - unobligated: unobligated16, - obligatedOther: budgetAuthority16 - unobligated16 - obligatedFiltered16, - obligationTotal: budgetAuthority16 - unobligated16 - }] + parsedYearYSeriesFiltered ] }; - expect(container.state()).toEqual(expectedState); + // don't compare the stacks + const containerState = container.state().data.toJS(); + delete containerState.stacks; + + expect(containerState).toEqual(expectedState); }); }); @@ -332,42 +267,18 @@ describe('AccountTimeVisualizationSectionContainer', () => { } ]); - const budgetAuthorityQ1 = parseFloat(mockReduxAccountQuartersFiltered.totals.budgetAuthority['2016 Q1']); - const obligatedFilteredQ1 = parseFloat(mockReduxAccountQuartersFiltered.totals.obligatedFiltered['2016 Q1']); - const unobligatedQ1 = parseFloat(mockReduxAccountQuartersFiltered.totals.unobligated['2016 Q1']); - const budgetAuthorityQ2 = parseFloat(mockReduxAccountQuartersFiltered.totals.budgetAuthority['2016 Q2']); - const obligatedFilteredQ2 = parseFloat(mockReduxAccountQuartersFiltered.totals.obligatedFiltered['2016 Q2']); - const unobligatedQ2 = parseFloat(mockReduxAccountQuartersFiltered.totals.unobligated['2016 Q2']); - const expectedState = { allY: [2696684.86, -5505246.42, 201404661.47, 198707976.61, 3851752, -4413237.11, 101905442.35, 5851779752], - groups: ["2016 Q1", "2016 Q2"], - hasFilteredObligated: true, - loading: false, - visualizationPeriod: "quarter", - xSeries: [["2016 Q1"], ["2016 Q2"]], - ySeries: [ - [{ - budgetAuthority: budgetAuthorityQ1, - obligatedFiltered: obligatedFilteredQ1, - obligatedOther: budgetAuthorityQ1 - unobligatedQ1 - obligatedFilteredQ1, - obligationTotal: budgetAuthorityQ1 - unobligatedQ1, - outlay: parseFloat(mockReduxAccountQuartersFiltered.totals.outlay['2016 Q1']), - unobligated: unobligatedQ1 - }], - [{ - budgetAuthority: budgetAuthorityQ2, - obligatedFiltered: obligatedFilteredQ2, - obligatedOther: budgetAuthorityQ2 - unobligatedQ2 - obligatedFilteredQ2, - obligationTotal: budgetAuthorityQ2 - unobligatedQ2, - outlay: parseFloat(mockReduxAccountQuartersFiltered.totals.outlay['2016 Q2']), - unobligated: unobligatedQ2 - }] - ] + xSeries: ["2016 Q1", "2016 Q2"], + ySeries: parsedQuarterYSeriesFiltered }; - expect(container.state()).toEqual(expectedState); + // don't compare the stacks + const containerState = container.state().data.toJS(); + delete containerState.stacks; + + expect(containerState).toEqual(expectedState); }); }); }); From 37069c85e9433e7387fe22c3b2d43c495d5893a3 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Mon, 31 Jul 2017 10:09:56 -0400 Subject: [PATCH 70/97] Update for API --- .../search/filters/recipient/RecipientNameDUNSContainer.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx b/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx index d825e4020d..207d5aca15 100644 --- a/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx +++ b/src/js/containers/search/filters/recipient/RecipientNameDUNSContainer.jsx @@ -101,9 +101,9 @@ export class RecipientNameDUNSContainer extends React.Component { this.recipientSearchRequest.promise .then((res) => { const parentResults = this.performSecondarySearch( - res.data.results.parent_recipient[0], 'parent_recipient_unique_id'); + res.data.results.parent_recipient, 'parent_recipient_unique_id'); const normalResults = this.performSecondarySearch( - res.data.results.recipient[0], 'recipient_unique_id'); + res.data.results.recipient, 'recipient_unique_id'); this.parseResults(parentResults, normalResults); }) .catch((err) => { From 1309be134c6580b6d1ee0e61bb1b099c082bf1fa Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Mon, 31 Jul 2017 11:39:54 -0400 Subject: [PATCH 71/97] Review Fixes: - Fixed removal of selected options from lists - added indexing style to local filtering - removed local filtering on PSC - Made generic files/functions where needed - Used new PropTypes module --- .../award/contract/ContractDetails.jsx | 7 +-- .../search/filters/cfda/SelectedCFDA.jsx | 9 ++-- .../search/filters/naics/SelectedNAICS.jsx | 9 ++-- .../search/filters/naics/ShownNAICS.jsx | 30 ----------- .../ShownValue.jsx} | 10 ++-- .../search/filters/psc/SelectedPSC.jsx | 11 ++-- .../search/filters/psc/ShownPSC.jsx | 30 ----------- .../search/filters/cfda/CFDAListContainer.jsx | 20 ++++---- .../filters/cfda/CFDASearchContainer.jsx | 3 +- .../filters/naics/NAICSListContainer.jsx | 20 ++++---- .../filters/naics/NAICSSearchContainer.jsx | 3 +- .../search/filters/psc/PSCListContainer.jsx | 28 ++++------ .../search/filters/psc/PSCSearchContainer.jsx | 3 +- src/js/helpers/otherFiltersFormatter.js | 20 +------- src/js/models/search/SearchOperation.js | 38 +++++++------- .../filters/cfda/CFDAListContainer-test.jsx | 51 +------------------ .../filters/naics/NAICSListContainer-test.jsx | 43 +--------------- .../filters/psc/PSCListContainer-test.jsx | 13 +---- 18 files changed, 82 insertions(+), 266 deletions(-) delete mode 100644 src/js/components/search/filters/naics/ShownNAICS.jsx rename src/js/components/search/filters/{cfda/ShownCFDA.jsx => otherFilters/ShownValue.jsx} (74%) delete mode 100644 src/js/components/search/filters/psc/ShownPSC.jsx diff --git a/src/js/components/award/contract/ContractDetails.jsx b/src/js/components/award/contract/ContractDetails.jsx index a943de5145..0c5c2f25a1 100644 --- a/src/js/components/award/contract/ContractDetails.jsx +++ b/src/js/components/award/contract/ContractDetails.jsx @@ -5,12 +5,13 @@ import React from 'react'; import moment from 'moment'; +import PropTypes from 'prop-types'; import DetailRow from '../DetailRow'; const propTypes = { - selectedAward: React.PropTypes.object, - seeAdditional: React.PropTypes.func, - maxChars: React.PropTypes.number + selectedAward: PropTypes.object, + seeAdditional: PropTypes.func, + maxChars: PropTypes.number }; export default class ContractDetails extends React.Component { diff --git a/src/js/components/search/filters/cfda/SelectedCFDA.jsx b/src/js/components/search/filters/cfda/SelectedCFDA.jsx index d47493a960..384bbf8245 100644 --- a/src/js/components/search/filters/cfda/SelectedCFDA.jsx +++ b/src/js/components/search/filters/cfda/SelectedCFDA.jsx @@ -7,7 +7,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as OtherFiltersFormatter from 'helpers/otherFiltersFormatter'; -import ShownCFDA from './ShownCFDA'; +import ShownValue from 'components/search/filters/otherFilters/ShownValue'; const propTypes = { selectedCFDA: PropTypes.object, @@ -20,11 +20,10 @@ export default class SelectedCFDA extends React.Component { this.props.selectedCFDA.entrySeq().forEach((entry) => { const key = entry[1].program_number; const cfda = entry[1].program_title; - const value = (); + removeValue={this.props.removeCFDA.bind(null, entry[1])} />); shownCFDA.push(value); }); diff --git a/src/js/components/search/filters/naics/SelectedNAICS.jsx b/src/js/components/search/filters/naics/SelectedNAICS.jsx index 2b3d3ecfaf..869c6c718d 100644 --- a/src/js/components/search/filters/naics/SelectedNAICS.jsx +++ b/src/js/components/search/filters/naics/SelectedNAICS.jsx @@ -7,7 +7,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as OtherFiltersFormatter from 'helpers/otherFiltersFormatter'; -import ShownNAICS from './ShownNAICS'; +import ShownValue from 'components/search/filters/otherFilters/ShownValue'; const propTypes = { selectedNAICS: PropTypes.object, @@ -20,11 +20,10 @@ export default class SelectedNAICS extends React.Component { this.props.selectedNAICS.entrySeq().forEach((entry) => { const naics = entry[1].naics; const description = entry[1].naics_description; - const value = (); + removeValue={this.props.removeNAICS.bind(null, entry[1])} />); shownNAICS.push(value); }); diff --git a/src/js/components/search/filters/naics/ShownNAICS.jsx b/src/js/components/search/filters/naics/ShownNAICS.jsx deleted file mode 100644 index 00de436858..0000000000 --- a/src/js/components/search/filters/naics/ShownNAICS.jsx +++ /dev/null @@ -1,30 +0,0 @@ -/** - * ShownNAICS.jsx - * Created by Emily Gullo 07/14/2017 - **/ - -import React from 'react'; -import PropTypes from 'prop-types'; -import * as Icons from 'components/sharedComponents/icons/Icons'; - -const propTypes = { - removeNAICS: PropTypes.func, - label: PropTypes.string -}; - -export default class ShownNAICS extends React.Component { - - render() { - return ( - - ); - } -} -ShownNAICS.propTypes = propTypes; diff --git a/src/js/components/search/filters/cfda/ShownCFDA.jsx b/src/js/components/search/filters/otherFilters/ShownValue.jsx similarity index 74% rename from src/js/components/search/filters/cfda/ShownCFDA.jsx rename to src/js/components/search/filters/otherFilters/ShownValue.jsx index 7d86e9e08c..b39ed36202 100644 --- a/src/js/components/search/filters/cfda/ShownCFDA.jsx +++ b/src/js/components/search/filters/otherFilters/ShownValue.jsx @@ -1,5 +1,5 @@ /** - * ShownCFDA.jsx + * ShownValue.jsx * Created by Emily Gullo 07/10/2017 **/ @@ -8,18 +8,18 @@ import PropTypes from 'prop-types'; import * as Icons from 'components/sharedComponents/icons/Icons'; const propTypes = { - removeCFDA: PropTypes.func, + removeValue: PropTypes.func, label: PropTypes.string }; -export default class ShownCFDA extends React.Component { +export default class ShownValue extends React.Component { render() { return ( - ); - } -} -ShownPSC.propTypes = propTypes; diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index afddee7a1c..394fa68d65 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -8,7 +8,7 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, omit, differenceWith, slice } from 'lodash'; import { isCancel } from 'axios'; -import { Search } from 'js-search'; +import { Search, PrefixIndexStrategy } from 'js-search'; import PropTypes from 'prop-types'; import * as SearchHelper from 'helpers/searchHelper'; @@ -18,8 +18,8 @@ import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete' const propTypes = { selectCFDA: PropTypes.func, - setAutocompleteCFDA: PropTypes.func, selectedCFDA: PropTypes.object, + setAutocompleteCFDA: PropTypes.func, autocompleteCFDA: PropTypes.array }; @@ -95,22 +95,22 @@ export class CFDAListContainer extends React.Component { const data = res.data.results; let autocompleteData = []; const search = new Search('program_number'); + // ordering by prefix if there are matches returned that begin w/ the exact text + search.indexStrategy = new PrefixIndexStrategy(); search.addIndex(['program_number']); search.addIndex(['program_title']); search.addDocuments(data); const results = search.search(this.state.cfdaSearchString); - let improvedResults = slice(results, 0, 10); - - // Remove 'identifier' from selected cfdas to enable comparison - improvedResults = this.props.selectedCFDA.toArray() - .map((cfda) => omit(cfda, 'identifier')); + const improvedResults = slice(results, 0, 10); - // Filter out any selected cfdas that may be in the result set + // Filter out any selected CFDA that may be in the result set + const selectedCFDA = + this.props.selectedCFDA.toArray().map((cfda) => omit(cfda, 'identifier')); if (improvedResults && improvedResults.length > 0) { - autocompleteData = differenceWith(data, improvedResults, isEqual); + autocompleteData = differenceWith(improvedResults, selectedCFDA, isEqual); } else { - autocompleteData = data; + autocompleteData = improvedResults; } this.setState({ diff --git a/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx b/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx index 6cdf40554b..2aafefa3f6 100644 --- a/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDASearchContainer.jsx @@ -6,13 +6,14 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import CFDASearch from 'components/search/filters/cfda/CFDASearch'; const propTypes = { - updateSelectedCFDA: React.PropTypes.func + updateSelectedCFDA: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/containers/search/filters/naics/NAICSListContainer.jsx b/src/js/containers/search/filters/naics/NAICSListContainer.jsx index efd9a79f06..4056a423c8 100644 --- a/src/js/containers/search/filters/naics/NAICSListContainer.jsx +++ b/src/js/containers/search/filters/naics/NAICSListContainer.jsx @@ -8,7 +8,7 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isEqual, omit, differenceWith, slice } from 'lodash'; import { isCancel } from 'axios'; -import { Search } from 'js-search'; +import { Search, PrefixIndexStrategy } from 'js-search'; import PropTypes from 'prop-types'; import * as SearchHelper from 'helpers/searchHelper'; @@ -18,8 +18,8 @@ import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete' const propTypes = { selectNAICS: PropTypes.func, - setAutocompleteNAICS: PropTypes.func, selectedNAICS: PropTypes.object, + setAutocompleteNAICS: PropTypes.func, autocompleteNAICS: PropTypes.array }; @@ -92,22 +92,22 @@ export class NAICSListContainer extends React.Component { const data = res.data.results; let autocompleteData = []; const search = new Search('naics'); + // ordering by prefix if there are matches returned that begin w/ the exact text + search.indexStrategy = new PrefixIndexStrategy(); search.addIndex(['naics']); search.addIndex(['naics_description']); search.addDocuments(data); - const results = search.search(this.state.cfdaSearchString); - let improvedResults = slice(results, 0, 10); - - // Remove 'identifier' from selected NAICS to enable comparison - improvedResults = this.props.selectedNAICS.toArray() - .map((naics) => omit(naics, 'identifier')); + const results = search.search(this.state.naicsSearchString); + const improvedResults = slice(results, 0, 10); // Filter out any selected NAICS that may be in the result set + const selectedNAICS = + this.props.selectedNAICS.toArray().map((naics) => omit(naics, 'identifier')); if (improvedResults && improvedResults.length > 0) { - autocompleteData = differenceWith(data, improvedResults, isEqual); + autocompleteData = differenceWith(improvedResults, selectedNAICS, isEqual); } else { - autocompleteData = data; + autocompleteData = improvedResults; } this.setState({ diff --git a/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx b/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx index b1cdd614a0..24274faf56 100644 --- a/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx +++ b/src/js/containers/search/filters/naics/NAICSSearchContainer.jsx @@ -6,13 +6,14 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import NAICSSearch from 'components/search/filters/naics/NAICSSearch'; const propTypes = { - updateSelectedNAICS: React.PropTypes.func + updateSelectedNAICS: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/containers/search/filters/psc/PSCListContainer.jsx b/src/js/containers/search/filters/psc/PSCListContainer.jsx index de7a33dc64..26a8295127 100644 --- a/src/js/containers/search/filters/psc/PSCListContainer.jsx +++ b/src/js/containers/search/filters/psc/PSCListContainer.jsx @@ -6,9 +6,8 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { isEqual, omit, differenceWith, slice } from 'lodash'; +import { isEqual, differenceWith, omit } from 'lodash'; import { isCancel } from 'axios'; -import { Search } from 'js-search'; import PropTypes from 'prop-types'; import * as SearchHelper from 'helpers/searchHelper'; @@ -18,8 +17,8 @@ import Autocomplete from 'components/sharedComponents/autocomplete/Autocomplete' const propTypes = { selectPSC: PropTypes.func, - setAutocompletePSC: PropTypes.func, selectedPSC: PropTypes.object, + setAutocompletePSC: PropTypes.func, autocompletePSC: PropTypes.array }; @@ -89,28 +88,21 @@ export class PSCListContainer extends React.Component { this.pscSearchRequest.promise .then((res) => { - const data = res.data.results; let autocompleteData = []; - const search = new Search('product_or_service_code'); - search.addIndex('product_or_service_code'); - search.addDocuments(data); - const results = search.search(this.state.pscSearchString); - let improvedResults = slice(results, 0, 10); - - // Remove 'identifier' from selected PSC to enable comparison - improvedResults = this.props.selectedPSC.toArray() - .map((psc) => omit(psc, 'identifier')); - - // Filter out any selected PSC that may be in the result set - if (improvedResults && improvedResults.length > 0) { - autocompleteData = differenceWith(data, improvedResults, isEqual); + const data = res.data.results; + + const selectedPSC = + this.props.selectedPSC.toArray().map((psc) => omit(psc, 'identifier')); + // Filter out any selectedPSC that may be in the result set + if (selectedPSC && selectedPSC.length > 0) { + autocompleteData = differenceWith(data, selectedPSC, isEqual); } else { autocompleteData = data; } this.setState({ - noResults: autocompleteData.length === 0 + noResults: data.length === 0 }); // Add search results to Redux diff --git a/src/js/containers/search/filters/psc/PSCSearchContainer.jsx b/src/js/containers/search/filters/psc/PSCSearchContainer.jsx index 63825d0a09..e22df67f1e 100644 --- a/src/js/containers/search/filters/psc/PSCSearchContainer.jsx +++ b/src/js/containers/search/filters/psc/PSCSearchContainer.jsx @@ -6,13 +6,14 @@ import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; import * as searchFilterActions from 'redux/actions/search/searchFilterActions'; import PSCSearch from 'components/search/filters/psc/PSCSearch'; const propTypes = { - updateSelectedPSC: React.PropTypes.func + updateSelectedPSC: PropTypes.func }; const ga = require('react-ga'); diff --git a/src/js/helpers/otherFiltersFormatter.js b/src/js/helpers/otherFiltersFormatter.js index ad417e6518..8b8bf1cda2 100644 --- a/src/js/helpers/otherFiltersFormatter.js +++ b/src/js/helpers/otherFiltersFormatter.js @@ -5,8 +5,8 @@ import { startCase, toLower } from 'lodash'; -export const formatCFDA = (cfda, description) => { - let displayValue = `${cfda}`; +export const formatValue = (value, description) => { + let displayValue = `${value}`; if (description !== null) { displayValue += ` | ${startCase(toLower(description))}`; @@ -14,19 +14,3 @@ export const formatCFDA = (cfda, description) => { return displayValue; }; - -export const formatNAICS = (naics, description) => { - let displayValue = `${naics}`; - - if (description !== null) { - displayValue += ` | ${startCase(toLower(description))}`; - } - - return displayValue; -}; - -export const formatPSC = (psc) => { - const displayValue = `${psc}`; - - return displayValue; -}; diff --git a/src/js/models/search/SearchOperation.js b/src/js/models/search/SearchOperation.js index fcbbae841a..df76423817 100644 --- a/src/js/models/search/SearchOperation.js +++ b/src/js/models/search/SearchOperation.js @@ -86,7 +86,7 @@ class SearchOperation { this.selectedCFDA = state.selectedCFDA.toArray(); this.selectedNAICS = state.selectedNAICS.toArray(); - this.selectesPSC = state.selectedPSC.toArray(); + this.selectedPSC = state.selectedPSC.toArray(); } commonParams() { @@ -178,24 +178,6 @@ class SearchOperation { } } - // Add cfda query - if (this.selectedCFDA.length > 0 && this.searchContext === 'award') { - filters.push(OtherFiltersQuery.buildCFDAQuery( - this.selectedCFDA, this.searchContext)); - } - - // Add naics query - if (this.selectedNAICS.length > 0 && this.searchContext === 'award') { - filters.push(OtherFiltersQuery.buildNAICSQuery( - this.selectedNAICS, this.searchContext)); - } - - // Add psc query - if (this.selectedPSC.length > 0 && this.searchContext === 'award') { - filters.push(OtherFiltersQuery.buildPSCQuery( - this.selectedPSC, this.searchContext)); - } - return filters; } @@ -221,6 +203,24 @@ class SearchOperation { this.fundingAgencies, this.awardingAgencies, this.searchContext)); } + // Add cfda query + if (this.selectedCFDA.length > 0 && this.searchContext === 'award') { + filters.push(OtherFiltersQuery.buildCFDAQuery( + this.selectedCFDA, this.searchContext)); + } + + // Add naics query + if (this.selectedNAICS.length > 0 && this.searchContext === 'award') { + filters.push(OtherFiltersQuery.buildNAICSQuery( + this.selectedNAICS, this.searchContext)); + } + + // Add psc query + if (this.selectedPSC.length > 0 && this.searchContext === 'award') { + filters.push(OtherFiltersQuery.buildPSCQuery( + this.selectedPSC, this.searchContext)); + } + return filters; } diff --git a/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx b/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx index 4f849c1746..34f81bbf31 100644 --- a/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx +++ b/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx @@ -218,56 +218,7 @@ describe('CFDAListContainer', () => { const cfdaListContainer = setup(Object.assign({}, initialFilters, { setAutocompleteCFDA: mockReduxAction, - autocompleteCFDA: [{ - program_number: '10.106', - popular_name: 'Disaster Relief Appropriations Act, EFRP', - program_title: 'Disaster Relief Appropriations Act, Emergency Forest Restoration Program' - }, - { - program_number: '10.108', - popular_name: '(LIP)', - program_title: 'Livestock Indemnity Program-2014 Farm Bill' - }, - { - program_number: '10.103', - popular_name: '', - program_title: '2009 Aquaculture Grant Program' - }, - { - program_number: '10.110', - popular_name: '(ELAP)', - program_title: 'Emergency Assistance for Livestock, Honeybees and Farm-Raised Fish Program-2014 Farm Bill' - }, - { - program_number: '10.104', - popular_name: '', - program_title: 'Poultry Loss Contract Grant Assistance Program' - }, - { - program_number: '10.102', - popular_name: '(EFRP)', - program_title: 'Emergency Forest Restoration Program ' - }, - { - program_number: '10.101', - popular_name: '', - program_title: 'Hawaii Sugar Disaster Program' - }, - { - program_number: '10.105', - popular_name: 'Disaster Relief Appropriations Act, ECP', - program_title: 'Disaster Relief Appropriations Act, Emergency Conservation Program' - }, - { - program_number: '10.109', - popular_name: '(LFP)', - program_title: 'Livestock Forage Program-2014 Farm Bill' - }, - { - program_number: '10.163', - popular_name: '', - program_title: 'Market Protection and Promotion' - }], + autocompleteCFDA: mockLocalCFDA, selectedCFDA: new OrderedMap() })); diff --git a/tests/containers/search/filters/naics/NAICSListContainer-test.jsx b/tests/containers/search/filters/naics/NAICSListContainer-test.jsx index b140bd2523..b3b78dffd5 100644 --- a/tests/containers/search/filters/naics/NAICSListContainer-test.jsx +++ b/tests/containers/search/filters/naics/NAICSListContainer-test.jsx @@ -218,48 +218,7 @@ describe('naicsListContainer', () => { const naicsListContainer = setup(Object.assign({}, initialFilters, { setAutocompleteNAICS: mockReduxAction, - autocompleteNAICS: [ - { - naics: "333318", - naics_description: "OTHER COMMERCIAL AND SERVICE INDUSTRY MACHINERY MANUFACTURING" - }, - { - naics: "333313", - naics_description: "OFFICE MACHINERY MANUFACTURING" - }, - { - naics: "333316", - naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" - }, - { - naics: "333314", - naics_description: "OPTICAL INSTRUMENT AND LENS MANUFACTURING" - }, - { - naics: "333315", - naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" - }, - { - naics: "339999", - naics_description: "ALL OTHER MISCELLANEOUS MANUFACTURING" - }, - { - naics: "333293", - naics_description: "PRINTING MACHINERY AND EQUIPMENT MANUFACTURING" - }, - { - naics: "339944", - naics_description: "CARBON PAPER AND INKED RIBBON MANUFACTURING" - }, - { - naics: "332993", - naics_description: "AMMUNITION (EXCEPT SMALL ARMS) MANUFACTURING" - }, - { - naics: "336111", - naics_description: "AUTOMOBILE MANUFACTURING" - } - ], + autocompleteNAICS: mockLocalNAICS, selectedNAICS: new OrderedMap() })); diff --git a/tests/containers/search/filters/psc/PSCListContainer-test.jsx b/tests/containers/search/filters/psc/PSCListContainer-test.jsx index fe71a8c82e..19adf63b7e 100644 --- a/tests/containers/search/filters/psc/PSCListContainer-test.jsx +++ b/tests/containers/search/filters/psc/PSCListContainer-test.jsx @@ -218,18 +218,7 @@ describe('pscListContainer', () => { const pscListContainer = setup(Object.assign({}, initialFilters, { setAutocompletePSC: mockReduxAction, - autocompletePSC: [ - { product_or_service_code: "1375" }, - { product_or_service_code: "R415" }, - { product_or_service_code: "8415" }, - { product_or_service_code: "S215" }, - { product_or_service_code: "R615" }, - { product_or_service_code: "1190" }, - { product_or_service_code: "1367" }, - { product_or_service_code: "1305" }, - { product_or_service_code: "6515" }, - { product_or_service_code: "6015" } - ], + autocompletePSC: mockLocalPSC, selectedPSC: new OrderedMap() })); From f3a3063e4c0b180f1a33bf5531207efeba00639e Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Mon, 31 Jul 2017 14:25:40 -0400 Subject: [PATCH 72/97] Use new PropTypes package for all components --- .../agencyLanding/AgencyLandingResultsSection.jsx | 9 +++++---- .../agencyLanding/AgencyLandingSearchBar.jsx | 3 ++- .../agencyLanding/table/AgencyLandingTable.jsx | 11 ++++++----- .../agencyLanding/table/cells/AgencyLinkCell.jsx | 9 +++++---- .../table/AgencyLandingHeaderCellContainer.jsx | 5 +++-- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx index 7296296942..be5bc741c8 100644 --- a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -4,16 +4,17 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import ResultsTableMessage from 'components/search/table/ResultsTableMessage'; import AgencyLandingHeaderCellContainer from 'containers/agencyLanding/table/AgencyLandingHeaderCellContainer'; import AgencyLandingTable from './table/AgencyLandingTable'; const propTypes = { - inFlight: React.PropTypes.bool, - results: React.PropTypes.array, - columns: React.PropTypes.array, - agencySearchString: React.PropTypes.string + inFlight: PropTypes.bool, + results: PropTypes.array, + columns: PropTypes.array, + agencySearchString: PropTypes.string }; export default class AgencyLandingResultsSection extends React.Component { diff --git a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx index 5813803518..74099817bb 100644 --- a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx +++ b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx @@ -4,11 +4,12 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { Search } from 'components/sharedComponents/icons/Icons'; const propTypes = { - handleTextInput: React.PropTypes.func.isRequired + handleTextInput: PropTypes.func.isRequired }; export default class AgencyLandingSearchBar extends React.Component { diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 034b7f836c..4104cbbdb5 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import Immutable from 'immutable'; import IBTable from 'components/sharedComponents/IBTable/IBTable'; @@ -12,11 +13,11 @@ import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableG import AgencyLinkCell from './cells/AgencyLinkCell'; const propTypes = { - batch: React.PropTypes.object, - results: React.PropTypes.array, - columns: React.PropTypes.array, - headerCellClass: React.PropTypes.func.isRequired, - visibleWidth: React.PropTypes.number + batch: PropTypes.object, + results: PropTypes.array, + columns: PropTypes.array, + headerCellClass: PropTypes.func.isRequired, + visibleWidth: PropTypes.number }; const rowHeight = 50; diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx index bb08d6ca35..13fa3a5b4f 100644 --- a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -4,12 +4,13 @@ **/ import React from 'react'; +import PropTypes from 'prop-types'; const propTypes = { - data: React.PropTypes.object, - rowIndex: React.PropTypes.number, - column: React.PropTypes.string, - isLastColumn: React.PropTypes.bool + data: PropTypes.object, + rowIndex: PropTypes.number, + column: PropTypes.string, + isLastColumn: PropTypes.bool }; export default class AgencyLinkCell extends React.Component { diff --git a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx index 86da4fd079..cd4b01b5fb 100644 --- a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx +++ b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; @@ -18,8 +19,8 @@ const actions = { }; const propTypes = { - setAgenciesOrder: React.PropTypes.func, - order: React.PropTypes.object + setAgenciesOrder: PropTypes.func, + order: PropTypes.object }; class AgencyLandingHeaderCellContainer extends React.Component { From 87e7b2dd634018c6724a76bf9ad1433da8fe2ede Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Mon, 31 Jul 2017 15:32:55 -0400 Subject: [PATCH 73/97] Fixing tests --- .../filters/cfda/CFDAListContainer-test.jsx | 5 +- .../search/filters/cfda/mockCFDA.js | 10 ++-- .../search/filters/cfda/mockLocalCFDA.js | 52 ------------------- .../filters/naics/NAICSListContainer-test.jsx | 5 +- .../search/filters/naics/mockLocalNAICS.js | 42 --------------- .../search/filters/naics/mockNAICS.js | 32 ++++++------ .../filters/psc/PSCListContainer-test.jsx | 5 +- .../search/filters/psc/mockLocalPSC.js | 12 ----- 8 files changed, 27 insertions(+), 136 deletions(-) delete mode 100644 tests/containers/search/filters/cfda/mockLocalCFDA.js delete mode 100644 tests/containers/search/filters/naics/mockLocalNAICS.js delete mode 100644 tests/containers/search/filters/psc/mockLocalPSC.js diff --git a/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx b/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx index 34f81bbf31..6db607caf6 100644 --- a/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx +++ b/tests/containers/search/filters/cfda/CFDAListContainer-test.jsx @@ -11,7 +11,6 @@ import { OrderedMap } from 'immutable'; import { CFDAListContainer } from 'containers/search/filters/cfda/CFDAListContainer'; import { mockCFDA } from './mockCFDA'; -import { mockLocalCFDA } from './mockLocalCFDA'; jest.mock('helpers/searchHelper', () => require('../searchHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -201,7 +200,7 @@ describe('CFDAListContainer', () => { expect(queryAutocompleteCFDASpy.callCount).toEqual(1); expect(parseAutocompleteCFDASpy.calledWith(queryAutocompleteCFDASpy)); expect(mockReduxActionCFDA).toHaveBeenCalledTimes(1); - expect(mockReduxActionCFDA.mock.calls[0]).toEqual([mockLocalCFDA]); + expect(mockReduxActionCFDA.mock.calls[0]).toEqual([mockCFDA.results]); // Reset spies queryAutocompleteCFDASpy.reset(); @@ -218,7 +217,7 @@ describe('CFDAListContainer', () => { const cfdaListContainer = setup(Object.assign({}, initialFilters, { setAutocompleteCFDA: mockReduxAction, - autocompleteCFDA: mockLocalCFDA, + autocompleteCFDA: mockCFDA.results, selectedCFDA: new OrderedMap() })); diff --git a/tests/containers/search/filters/cfda/mockCFDA.js b/tests/containers/search/filters/cfda/mockCFDA.js index 11ccecdde5..eef40fd548 100644 --- a/tests/containers/search/filters/cfda/mockCFDA.js +++ b/tests/containers/search/filters/cfda/mockCFDA.js @@ -15,11 +15,6 @@ export const mockCFDA = { popular_name: "", program_title: "2009 Aquaculture Grant Program" }, - { - program_number: "10.110", - popular_name: "(ELAP)", - program_title: "Emergency Assistance for Livestock, Honeybees and Farm-Raised Fish Program-2014 Farm Bill" - }, { program_number: "10.104", popular_name: "", @@ -45,6 +40,11 @@ export const mockCFDA = { popular_name: "(LFP)", program_title: "Livestock Forage Program-2014 Farm Bill" }, + { + program_number: "10.110", + popular_name: "(ELAP)", + program_title: "Emergency Assistance for Livestock, Honeybees and Farm-Raised Fish Program-2014 Farm Bill" + }, { program_number: "10.163", popular_name: "", diff --git a/tests/containers/search/filters/cfda/mockLocalCFDA.js b/tests/containers/search/filters/cfda/mockLocalCFDA.js deleted file mode 100644 index 34fb5775f7..0000000000 --- a/tests/containers/search/filters/cfda/mockLocalCFDA.js +++ /dev/null @@ -1,52 +0,0 @@ -export const mockLocalCFDA = [ - { - program_number: "10.106", - popular_name: "Disaster Relief Appropriations Act, EFRP", - program_title: "Disaster Relief Appropriations Act, Emergency Forest Restoration Program" - }, - { - program_number: "10.108", - popular_name: "(LIP)", - program_title: "Livestock Indemnity Program-2014 Farm Bill" - }, - { - program_number: "10.103", - popular_name: "", - program_title: "2009 Aquaculture Grant Program" - }, - { - program_number: "10.110", - popular_name: "(ELAP)", - program_title: "Emergency Assistance for Livestock, Honeybees and Farm-Raised Fish Program-2014 Farm Bill" - }, - { - program_number: "10.104", - popular_name: "", - program_title: "Poultry Loss Contract Grant Assistance Program" - }, - { - program_number: "10.102", - popular_name: "(EFRP)", - program_title: "Emergency Forest Restoration Program " - }, - { - program_number: "10.101", - popular_name: "", - program_title: "Hawaii Sugar Disaster Program" - }, - { - program_number: "10.105", - popular_name: "Disaster Relief Appropriations Act, ECP", - program_title: "Disaster Relief Appropriations Act, Emergency Conservation Program" - }, - { - program_number: "10.109", - popular_name: "(LFP)", - program_title: "Livestock Forage Program-2014 Farm Bill" - }, - { - program_number: "10.163", - popular_name: "", - program_title: "Market Protection and Promotion" - } -]; diff --git a/tests/containers/search/filters/naics/NAICSListContainer-test.jsx b/tests/containers/search/filters/naics/NAICSListContainer-test.jsx index b3b78dffd5..7ea3424a2f 100644 --- a/tests/containers/search/filters/naics/NAICSListContainer-test.jsx +++ b/tests/containers/search/filters/naics/NAICSListContainer-test.jsx @@ -11,7 +11,6 @@ import { OrderedMap } from 'immutable'; import { NAICSListContainer } from 'containers/search/filters/naics/NAICSListContainer'; import { mockNAICS } from './mockNAICS'; -import { mockLocalNAICS } from './mockLocalNAICS'; jest.mock('helpers/searchHelper', () => require('../searchHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -201,7 +200,7 @@ describe('naicsListContainer', () => { expect(queryAutocompleteNAICSSpy.callCount).toEqual(1); expect(parseAutocompleteNAICSSpy.calledWith(queryAutocompleteNAICSSpy)); expect(mockReduxActionNAICS).toHaveBeenCalledTimes(1); - expect(mockReduxActionNAICS.mock.calls[0]).toEqual([mockLocalNAICS]); + expect(mockReduxActionNAICS.mock.calls[0]).toEqual([mockNAICS.results]); // Reset spies queryAutocompleteNAICSSpy.reset(); @@ -218,7 +217,7 @@ describe('naicsListContainer', () => { const naicsListContainer = setup(Object.assign({}, initialFilters, { setAutocompleteNAICS: mockReduxAction, - autocompleteNAICS: mockLocalNAICS, + autocompleteNAICS: mockNAICS.results, selectedNAICS: new OrderedMap() })); diff --git a/tests/containers/search/filters/naics/mockLocalNAICS.js b/tests/containers/search/filters/naics/mockLocalNAICS.js deleted file mode 100644 index 9949314ad7..0000000000 --- a/tests/containers/search/filters/naics/mockLocalNAICS.js +++ /dev/null @@ -1,42 +0,0 @@ -export const mockLocalNAICS = [ - { - naics: "333318", - naics_description: "OTHER COMMERCIAL AND SERVICE INDUSTRY MACHINERY MANUFACTURING" - }, - { - naics: "333313", - naics_description: "OFFICE MACHINERY MANUFACTURING" - }, - { - naics: "333316", - naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" - }, - { - naics: "333314", - naics_description: "OPTICAL INSTRUMENT AND LENS MANUFACTURING" - }, - { - naics: "333315", - naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" - }, - { - naics: "339999", - naics_description: "ALL OTHER MISCELLANEOUS MANUFACTURING" - }, - { - naics: "333293", - naics_description: "PRINTING MACHINERY AND EQUIPMENT MANUFACTURING" - }, - { - naics: "339944", - naics_description: "CARBON PAPER AND INKED RIBBON MANUFACTURING" - }, - { - naics: "332993", - naics_description: "AMMUNITION (EXCEPT SMALL ARMS) MANUFACTURING" - }, - { - naics: "336111", - naics_description: "AUTOMOBILE MANUFACTURING" - } -]; diff --git a/tests/containers/search/filters/naics/mockNAICS.js b/tests/containers/search/filters/naics/mockNAICS.js index f7e88ac8fc..ea4c553170 100644 --- a/tests/containers/search/filters/naics/mockNAICS.js +++ b/tests/containers/search/filters/naics/mockNAICS.js @@ -1,16 +1,16 @@ export const mockNAICS = { results: [ { - naics: "333318", - naics_description: "OTHER COMMERCIAL AND SERVICE INDUSTRY MACHINERY MANUFACTURING" + naics: "332993", + naics_description: "AMMUNITION (EXCEPT SMALL ARMS) MANUFACTURING" }, { - naics: "333313", - naics_description: "OFFICE MACHINERY MANUFACTURING" + naics: "333293", + naics_description: "PRINTING MACHINERY AND EQUIPMENT MANUFACTURING" }, { - naics: "333316", - naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" + naics: "333313", + naics_description: "OFFICE MACHINERY MANUFACTURING" }, { naics: "333314", @@ -21,24 +21,24 @@ export const mockNAICS = { naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" }, { - naics: "339999", - naics_description: "ALL OTHER MISCELLANEOUS MANUFACTURING" + naics: "333316", + naics_description: "PHOTOGRAPHIC AND PHOTOCOPYING EQUIPMENT MANUFACTURING" }, { - naics: "333293", - naics_description: "PRINTING MACHINERY AND EQUIPMENT MANUFACTURING" + naics: "333318", + naics_description: "OTHER COMMERCIAL AND SERVICE INDUSTRY MACHINERY MANUFACTURING" }, { - naics: "339944", - naics_description: "CARBON PAPER AND INKED RIBBON MANUFACTURING" + naics: "336111", + naics_description: "AUTOMOBILE MANUFACTURING" }, { - naics: "332993", - naics_description: "AMMUNITION (EXCEPT SMALL ARMS) MANUFACTURING" + naics: "339944", + naics_description: "CARBON PAPER AND INKED RIBBON MANUFACTURING" }, { - naics: "336111", - naics_description: "AUTOMOBILE MANUFACTURING" + naics: "339999", + naics_description: "ALL OTHER MISCELLANEOUS MANUFACTURING" } ] }; diff --git a/tests/containers/search/filters/psc/PSCListContainer-test.jsx b/tests/containers/search/filters/psc/PSCListContainer-test.jsx index 19adf63b7e..bb07cf48ee 100644 --- a/tests/containers/search/filters/psc/PSCListContainer-test.jsx +++ b/tests/containers/search/filters/psc/PSCListContainer-test.jsx @@ -11,7 +11,6 @@ import { OrderedMap } from 'immutable'; import { PSCListContainer } from 'containers/search/filters/psc/PSCListContainer'; import { mockPSC } from './mockPSC'; -import { mockLocalPSC } from './mockLocalPSC'; jest.mock('helpers/searchHelper', () => require('../searchHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -201,7 +200,7 @@ describe('pscListContainer', () => { expect(queryAutocompletePSCSpy.callCount).toEqual(1); expect(parseAutocompletePSCSpy.calledWith(queryAutocompletePSCSpy)); expect(mockReduxActionPSC).toHaveBeenCalledTimes(1); - expect(mockReduxActionPSC.mock.calls[0]).toEqual([mockLocalPSC]); + expect(mockReduxActionPSC.mock.calls[0]).toEqual([mockPSC.results]); // Reset spies queryAutocompletePSCSpy.reset(); @@ -218,7 +217,7 @@ describe('pscListContainer', () => { const pscListContainer = setup(Object.assign({}, initialFilters, { setAutocompletePSC: mockReduxAction, - autocompletePSC: mockLocalPSC, + autocompletePSC: mockPSC.results, selectedPSC: new OrderedMap() })); diff --git a/tests/containers/search/filters/psc/mockLocalPSC.js b/tests/containers/search/filters/psc/mockLocalPSC.js deleted file mode 100644 index bf7f983d4b..0000000000 --- a/tests/containers/search/filters/psc/mockLocalPSC.js +++ /dev/null @@ -1,12 +0,0 @@ -export const mockLocalPSC = [ - { product_or_service_code: "1375" }, - { product_or_service_code: "R415" }, - { product_or_service_code: "8415" }, - { product_or_service_code: "S215" }, - { product_or_service_code: "R615" }, - { product_or_service_code: "1190" }, - { product_or_service_code: "1367" }, - { product_or_service_code: "1305" }, - { product_or_service_code: "6515" }, - { product_or_service_code: "6015" } -]; From 36dfb4fbc73e4a68f6ab27dedb87e5e8df3e3191 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Mon, 31 Jul 2017 17:23:51 -0400 Subject: [PATCH 74/97] Eliminate autocomplete query and just use matched string results --- .../table/AgencyLandingTable.jsx | 3 +- .../table/cells/AgencyLinkCell.jsx | 11 ++- .../agencyLanding/AgencyLandingContainer.jsx | 14 ++- .../AgencyLandingSearchBarContainer.jsx | 86 ++++++++----------- src/js/helpers/agencyLandingHelper.js | 15 ---- .../AgencyLandingContainer-test.jsx | 11 +-- .../AgencyLandingSearchBarContainer-test.jsx | 56 ++++++------ .../agencyLanding/mockToptierAgencies.js | 31 ++++++- 8 files changed, 114 insertions(+), 113 deletions(-) diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 4104cbbdb5..99a854cf4b 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -89,7 +89,8 @@ export default class AgencyLandingTable extends React.PureComponent { diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx index 13fa3a5b4f..126ee9f00b 100644 --- a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -7,17 +7,18 @@ import React from 'react'; import PropTypes from 'prop-types'; const propTypes = { - data: PropTypes.object, + name: PropTypes.array, rowIndex: PropTypes.number, column: PropTypes.string, - isLastColumn: PropTypes.bool + isLastColumn: PropTypes.bool, + id: PropTypes.number }; export default class AgencyLinkCell extends React.Component { render() { // cell needs to have some content or it will collapse // replace with a   if there's no data - let content = this.props.data; + let content = this.props.name; if (!content) { content = "\u00A0"; } @@ -36,7 +37,9 @@ export default class AgencyLinkCell extends React.Component { return ( ); diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 7cf26b5757..3efbea7dca 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -149,15 +149,16 @@ export class AgencyLandingContainer extends React.Component { parseAgencies(data) { const agencies = []; - const showAllAgencies = this.props.autocompleteAgencies.length === 0 && !this.state.noResults; + const showAllAgencies = this.props.autocompleteAgencies.length === 0 + && !this.state.noResults; data.results.forEach((item) => { - // If there is no search term, show all agencies. Otherwise, only show agencies that match - // the search input + // If there is no search term, show all agencies. + // Otherwise, only show agencies that match the search input. if (showAllAgencies || (this.props.autocompleteAgencies.indexOf(parseFloat(item.agency_id)) > -1)) { // Create a link to the agency's profile page - let linkText = item.agency_name; + let linkText = [item.agency_name]; // If the user has entered a search term, highlight the matched substring if (this.state.agencySearchString) { @@ -165,9 +166,6 @@ export class AgencyLandingContainer extends React.Component { {match} )); } - const link = ( - {linkText} - ); // Format budget authority amount const formattedCurrency = @@ -187,7 +185,7 @@ export class AgencyLandingContainer extends React.Component { const agencyObject = { agency_id: item.agency_id, - agency_name: link, + agency_name: linkText, budget_authority_amount: formattedCurrency, percentage_of_total_budget_authority: percent }; diff --git a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx index d4f1238773..a69fd4229f 100644 --- a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx @@ -7,11 +7,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { isCancel } from 'axios'; import { Search } from 'js-search'; +import Immutable from 'immutable'; import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; -import * as AgencyLandingHelper from 'helpers/agencyLandingHelper'; import AgencyLandingSearchBar from 'components/agencyLanding/AgencyLandingSearchBar'; @@ -19,7 +18,8 @@ const propTypes = { setAgencySearchString: PropTypes.func, setNoResults: PropTypes.func, setAutocompleteAgencies: PropTypes.func, - autocompleteAgencies: PropTypes.array + autocompleteAgencies: PropTypes.array, + agencies: PropTypes.instanceOf(Immutable.OrderedSet) }; export class AgencyLandingSearchBarContainer extends React.Component { @@ -57,13 +57,11 @@ export class AgencyLandingSearchBarContainer extends React.Component { // Perform search if user doesn't type again for 300ms this.timeout = window.setTimeout(() => { - this.queryAutocompleteAgencies(input); + this.performSecondarySearch(input); }, 300); } - queryAutocompleteAgencies(input) { - this.props.setNoResults(false); - + performSecondarySearch(input) { // Only search if input is 2 or more characters if (input.length >= 2) { this.props.setAgencySearchString(input); @@ -71,57 +69,42 @@ export class AgencyLandingSearchBarContainer extends React.Component { agencySearchString: input }); - const agencySearchParams = { - search_text: input - }; - - this.agencySearchRequest = AgencyLandingHelper.fetchSearchResults(agencySearchParams); - - this.agencySearchRequest.promise - .then((res) => { - this.performSecondarySearch(res.data.results); - }) - .catch((err) => { - if (!isCancel(err)) { - this.props.setNoResults(true); - } - }); - } - else if (this.agencySearchRequest) { - // A request is currently in-flight, cancel it - this.agencySearchRequest.cancel(); - } - else { - this.props.setAgencySearchString(''); - this.setState({ - agencySearchString: '' + // Convert agency Records to objects + const data = []; + this.props.agencies.forEach((agency) => { + const agencyObject = agency.toJS(); + data.push(agencyObject); }); - } - } - performSecondarySearch(data) { - // Search within the returned data - // Create a search index with the API response records - const search = new Search('agency_id'); - search.addIndex('agency_name'); + // Create a search index with the API response records + const search = new Search('agency_id'); + search.addIndex('agency_name'); - // Add the API response as the data source to search within - search.addDocuments(data); + // Add the API response as the data source to search within + search.addDocuments(data); - // Use the JS search library to search within the records - const results = search.search(this.state.agencySearchString); + // Use the JS search library to search within the records + const results = search.search(this.state.agencySearchString); - const matchedAgencyIds = []; - results.forEach((item) => { - matchedAgencyIds.push(item.agency_id); - }); + const matchedAgencyIds = []; + results.forEach((item) => { + matchedAgencyIds.push(item.agency_id); + }); - // Add search results to Redux - this.props.setAutocompleteAgencies( - matchedAgencyIds - ); + // Add search results to Redux + this.props.setAutocompleteAgencies( + matchedAgencyIds + ); - this.props.setNoResults(matchedAgencyIds.length === 0); + this.props.setNoResults(matchedAgencyIds.length === 0); + } + else { + this.props.setNoResults(false); + this.props.setAgencySearchString(''); + this.setState({ + agencySearchString: '' + }); + } } render() { @@ -136,6 +119,7 @@ AgencyLandingSearchBarContainer.propTypes = propTypes; export default connect( (state) => ({ + agencies: state.agencyLanding.agencies, autocompleteAgencies: state.agencyLanding.autocompleteAgencies }), (dispatch) => bindActionCreators(agencyLandingActions, dispatch) diff --git a/src/js/helpers/agencyLandingHelper.js b/src/js/helpers/agencyLandingHelper.js index dfec1cf068..812c4ec94f 100644 --- a/src/js/helpers/agencyLandingHelper.js +++ b/src/js/helpers/agencyLandingHelper.js @@ -23,18 +23,3 @@ export const fetchAllAgencies = (params) => { }; }; -export const fetchSearchResults = (params) => { - const source = CancelToken.source(); - return { - promise: Axios.request({ - url: 'v2/autocomplete/toptier_agency/', - baseURL: kGlobalConstants.API, - method: 'post', - data: params, - cancelToken: source.token - }), - cancel() { - source.cancel(); - } - }; -}; diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index adc27d2b62..73f9848640 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -109,25 +109,26 @@ describe('AgencyLandingContainer', () => { describe('parseAgencies', () => { it('should parse the API response and overwrite the Redux agencies', (done) => { - const expected = new Immutable.OrderedSet([ + const expected = Object.assign({},new Immutable.OrderedSet([ new Agency({ agency_id: 1, - agency_name: Test 1, + agency_name: ['Agency 1'], budget_authority_amount: "$1,234,567", percentage_of_total_budget_authority: "1.21%" }), new Agency({ agency_id: 2, - agency_name: Test 2, + agency_name: ['Agency 2'], budget_authority_amount: "$2,345,678", percentage_of_total_budget_authority: "2.32%" }) - ]); + ])); + delete expected._jsid; const reduxAction = jest.fn((args) => { const model = Object.assign({}, new Immutable.OrderedSet(args)); - delete model._jsid; + //delete model._jsid; expect(model).toEqual(expected); done(); diff --git a/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx index 7a261bbb32..ec793b27da 100644 --- a/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx @@ -13,6 +13,7 @@ import { AgencyLandingSearchBarContainer } from import { AgencyLandingSearchBar } from 'components/agencyLanding/AgencyLandingSearchBar'; import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; +import { mockAgencies } from './mockToptierAgencies'; jest.mock('helpers/agencyLandingHelper', () => require('./agencyLandingHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -27,7 +28,8 @@ describe('AgencyLandingSearchBarContainer', () => { setAgencySearchString: jest.fn(), setNoResults: jest.fn(), setAutocompleteAgencies: agencyLandingActions.setAutocompleteAgencies, - autocompleteAgencies: [] + autocompleteAgencies: [], + agencies: mockAgencies }); const searchQuery = { @@ -55,13 +57,14 @@ describe('AgencyLandingSearchBarContainer', () => { handleTextInputSpy.reset(); }); - it('should call the queryAutocompleteAgencies method after text input', () => { + it('should call the performSecondarySearch method after text input', () => { // setup the search bar container and call the function to type a single letter const searchBarContainer = setup({ setAgencySearchString: jest.fn(), setNoResults: jest.fn(), setAutocompleteAgencies: agencyLandingActions.setAutocompleteAgencies, - autocompleteAgencies: [] + autocompleteAgencies: [], + agencies: mockAgencies }); const searchQuery = { @@ -72,8 +75,8 @@ describe('AgencyLandingSearchBarContainer', () => { const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), 'handleTextInput'); - const queryAutocompleteAgenciesSpy = sinon.spy(searchBarContainer.instance(), - 'queryAutocompleteAgencies'); + const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), + 'performSecondarySearch'); // Call handleTextInput function searchBarContainer.instance().handleTextInput(searchQuery); @@ -83,11 +86,11 @@ describe('AgencyLandingSearchBarContainer', () => { // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); - expect(queryAutocompleteAgenciesSpy.callCount).toEqual(1); + expect(performSecondarySearchSpy.callCount).toEqual(1); // reset the spies handleTextInputSpy.reset(); - queryAutocompleteAgenciesSpy.reset(); + performSecondarySearchSpy.reset(); }); it('should not search when only one character has been input', () => { // setup mock redux actions for handling search results @@ -98,11 +101,12 @@ describe('AgencyLandingSearchBarContainer', () => { setAgencySearchString: jest.fn(), setNoResults: jest.fn(), setAutocompleteAgencies: mockReduxAction, - autocompleteAgencies: [] + autocompleteAgencies: [], + agencies: mockAgencies }); - const queryAutocompleteAgenciesSpy = sinon.spy(searchBarContainer.instance(), - 'queryAutocompleteAgencies'); + const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), + 'performSecondarySearch'); const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), 'handleTextInput'); @@ -120,13 +124,13 @@ describe('AgencyLandingSearchBarContainer', () => { // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); - expect(queryAutocompleteAgenciesSpy.callCount).toEqual(1); + expect(performSecondarySearchSpy.callCount).toEqual(1); // The redux action is called once in handleTextInput to reset expect(mockReduxAction).toHaveBeenCalledTimes(1); // reset the mocks and spies handleTextInputSpy.reset(); - queryAutocompleteAgenciesSpy.reset(); + performSecondarySearchSpy.reset(); }); it('should perform the search when more than one character has been entered', () => { @@ -138,14 +142,15 @@ describe('AgencyLandingSearchBarContainer', () => { setAgencySearchString: jest.fn(), setNoResults: jest.fn(), setAutocompleteAgencies: mockReduxAction, - autocompleteAgencies: [] + autocompleteAgencies: [], + agencies: mockAgencies }); // set up spies const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), 'handleTextInput'); - const queryAutocompleteAgenciesSpy = sinon.spy(searchBarContainer.instance(), - 'queryAutocompleteAgencies'); + const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), + 'performSecondarySearch'); const searchQuery = { target: { @@ -161,16 +166,17 @@ describe('AgencyLandingSearchBarContainer', () => { // everything should be updated now expect(handleTextInputSpy.callCount).toEqual(1); - expect(queryAutocompleteAgenciesSpy.calledWith(handleTextInputSpy)); + expect(performSecondarySearchSpy.calledWith(handleTextInputSpy)); // Reset spies handleTextInputSpy.reset(); - queryAutocompleteAgenciesSpy.reset(); + performSecondarySearchSpy.reset(); }); - it('should populate Agencies after performing the search', async () => { + it('should populate Agencies with matching results after performing the search', () => { // Setup redux state - const reduxState = [1, 2]; + // Only id's 1 & 3 have agency names with the substring we are using + const reduxState = [1, 3]; // setup mock redux actions for handling search results const mockReduxAction = jest.fn((args) => { @@ -182,24 +188,20 @@ describe('AgencyLandingSearchBarContainer', () => { setAgencySearchString: jest.fn(), setNoResults: jest.fn(), setAutocompleteAgencies: mockReduxAction, - autocompleteAgencies: reduxState + autocompleteAgencies: reduxState, + agencies: mockAgencies }); // Set up spies - const queryAutocompleteAgenciesSpy = sinon.spy(searchBarContainer.instance(), - 'queryAutocompleteAgencies'); const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), 'performSecondarySearch'); - searchBarContainer.instance().queryAutocompleteAgencies('Department of'); - await searchBarContainer.instance().agencySearchRequest.promise; + searchBarContainer.instance().performSecondarySearch('Agen'); - expect(queryAutocompleteAgenciesSpy.callCount).toEqual(1); - expect(performSecondarySearchSpy.calledWith(queryAutocompleteAgenciesSpy)); + expect(performSecondarySearchSpy.callCount).toEqual(1); expect(mockReduxAction).toHaveBeenCalled(); // Reset spies - queryAutocompleteAgenciesSpy.reset(); performSecondarySearchSpy.reset(); }); }); diff --git a/tests/containers/agencyLanding/mockToptierAgencies.js b/tests/containers/agencyLanding/mockToptierAgencies.js index 98731e439b..65e1bd0a33 100644 --- a/tests/containers/agencyLanding/mockToptierAgencies.js +++ b/tests/containers/agencyLanding/mockToptierAgencies.js @@ -5,13 +5,13 @@ export const mockData = { results: [ { agency_id: 1, - agency_name: 'Test 1', + agency_name: 'Agency 1', budget_authority_amount: '1234567', percentage_of_total_budget_authority: '0.01211' }, { agency_id: 2, - agency_name: 'Test 2', + agency_name: 'Agency 2', budget_authority_amount: '2345678', percentage_of_total_budget_authority: '0.02322' } @@ -43,3 +43,30 @@ export const mockAgenciesOrder = { direction: 'desc' }; +export const mockAgencies = [ + new Agency( + { + agency_id: 1, + agency_name: 'Agency 1', + budget_authority_amount: '1234567', + percentage_of_total_budget_authority: '0.01211' + } + ), + new Agency( + { + agency_id: 2, + agency_name: 'Test 2', + budget_authority_amount: '2345678', + percentage_of_total_budget_authority: '0.02322' + } + ), + new Agency( + { + agency_id: 3, + agency_name: 'Agency 3', + budget_authority_amount: '2345678', + percentage_of_total_budget_authority: '0.02322' + } + ) +]; + From c8ed041a4f82df46c682f43794c21933dfc1c4bf Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Mon, 31 Jul 2017 17:29:34 -0400 Subject: [PATCH 75/97] Updated agency name default sort direction and tests --- src/js/dataMapping/agencyLanding/agenciesTableFields.js | 2 +- src/js/redux/reducers/agencyLanding/agencyLandingReducer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/dataMapping/agencyLanding/agenciesTableFields.js b/src/js/dataMapping/agencyLanding/agenciesTableFields.js index dd8445f3d4..ff35b03e98 100644 --- a/src/js/dataMapping/agencyLanding/agenciesTableFields.js +++ b/src/js/dataMapping/agencyLanding/agenciesTableFields.js @@ -1,6 +1,6 @@ const agenciesTableFields = { defaultSortDirection: { - agency_name: 'desc', + agency_name: 'asc', budget_authority_amount: 'desc', percentage_of_total_budget_authority: 'desc' }, diff --git a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js index 3ffbbded6f..7107fa3cba 100644 --- a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js +++ b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js @@ -17,7 +17,7 @@ const initialState = { agencies: new OrderedSet(), agenciesOrder: { field: 'agency_name', - direction: 'desc' + direction: 'asc' }, agenciesMeta: { batch: { From f59ab341a7b330d1186623dd9e62ad0550aa2fec Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Tue, 1 Aug 2017 07:38:14 -0400 Subject: [PATCH 76/97] Requested changes: - text updates - removal of specific searchContext in SearchOperation - removing unneeded comment --- src/js/containers/search/filters/cfda/CFDAListContainer.jsx | 2 +- .../containers/search/filters/naics/NAICSListContainer.jsx | 2 +- src/js/containers/search/filters/psc/PSCListContainer.jsx | 2 +- src/js/models/search/SearchOperation.js | 6 +++--- src/js/models/search/queryBuilders/OtherFiltersQuery.js | 1 - 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx index 394fa68d65..91043fe0ce 100644 --- a/src/js/containers/search/filters/cfda/CFDAListContainer.jsx +++ b/src/js/containers/search/filters/cfda/CFDAListContainer.jsx @@ -159,7 +159,7 @@ export class CFDAListContainer extends React.Component { values={this.state.autocompleteCFDA} handleTextInput={this.handleTextInput} onSelect={this.props.selectCFDA} - placeholder="eg: 10.553 - School Breakfast Program" + placeholder="e.g., 10.553 - School Breakfast Program" errorHeader="Unknown CFDA" errorMessage="We were unable to find that CFDA." ref={(input) => { diff --git a/src/js/containers/search/filters/naics/NAICSListContainer.jsx b/src/js/containers/search/filters/naics/NAICSListContainer.jsx index 4056a423c8..ed86dfc62a 100644 --- a/src/js/containers/search/filters/naics/NAICSListContainer.jsx +++ b/src/js/containers/search/filters/naics/NAICSListContainer.jsx @@ -156,7 +156,7 @@ export class NAICSListContainer extends React.Component { values={this.state.autocompleteNAICS} handleTextInput={this.handleTextInput} onSelect={this.props.selectNAICS} - placeholder="eg: 33641 - Aircraft Manufacturing" + placeholder="e.g., 336411 - Aircraft Manufacturing" errorHeader="Unknown NAICS" errorMessage="We were unable to find that NAICS." ref={(input) => { diff --git a/src/js/containers/search/filters/psc/PSCListContainer.jsx b/src/js/containers/search/filters/psc/PSCListContainer.jsx index 26a8295127..50024e0bf6 100644 --- a/src/js/containers/search/filters/psc/PSCListContainer.jsx +++ b/src/js/containers/search/filters/psc/PSCListContainer.jsx @@ -147,7 +147,7 @@ export class PSCListContainer extends React.Component { values={this.state.autocompletePSC} handleTextInput={this.handleTextInput} onSelect={this.props.selectPSC} - placeholder="eg: 1510 - Aircraft, Fixed Wing" + placeholder="e.g., 1510 - Aircraft, Fixed Wing" errorHeader="Unknown PSC" errorMessage="We were unable to find that PSC." ref={(input) => { diff --git a/src/js/models/search/SearchOperation.js b/src/js/models/search/SearchOperation.js index df76423817..72e662390a 100644 --- a/src/js/models/search/SearchOperation.js +++ b/src/js/models/search/SearchOperation.js @@ -204,19 +204,19 @@ class SearchOperation { } // Add cfda query - if (this.selectedCFDA.length > 0 && this.searchContext === 'award') { + if (this.selectedCFDA.length > 0) { filters.push(OtherFiltersQuery.buildCFDAQuery( this.selectedCFDA, this.searchContext)); } // Add naics query - if (this.selectedNAICS.length > 0 && this.searchContext === 'award') { + if (this.selectedNAICS.length > 0) { filters.push(OtherFiltersQuery.buildNAICSQuery( this.selectedNAICS, this.searchContext)); } // Add psc query - if (this.selectedPSC.length > 0 && this.searchContext === 'award') { + if (this.selectedPSC.length > 0) { filters.push(OtherFiltersQuery.buildPSCQuery( this.selectedPSC, this.searchContext)); } diff --git a/src/js/models/search/queryBuilders/OtherFiltersQuery.js b/src/js/models/search/queryBuilders/OtherFiltersQuery.js index c4a97dd067..7103b1dbd5 100644 --- a/src/js/models/search/queryBuilders/OtherFiltersQuery.js +++ b/src/js/models/search/queryBuilders/OtherFiltersQuery.js @@ -24,7 +24,6 @@ export const buildCFDAQuery = (cfdaGroup, searchContext = 'award') => { export const buildNAICSQuery = (naicsGroup, searchContext = 'award') => { const field = FilterFields[`${searchContext}Fields`].naics; - // if context is award and account leave set empty const naicsSet = []; From 95ed0b8767fa6ab6b0ec24fd5100a53841e88dc1 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 1 Aug 2017 14:08:44 -0400 Subject: [PATCH 77/97] Container tests --- .../agency/visualizations/RecipientContainer-test.jsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/containers/agency/visualizations/RecipientContainer-test.jsx b/tests/containers/agency/visualizations/RecipientContainer-test.jsx index 23f0325e24..56ac62f2cb 100644 --- a/tests/containers/agency/visualizations/RecipientContainer-test.jsx +++ b/tests/containers/agency/visualizations/RecipientContainer-test.jsx @@ -48,10 +48,12 @@ describe('RecipientContainer', () => { loadDataSpy.reset(); }); - it('should make a new API call when the inbound agency ID prop changes', () => { + it('should make a new API call when the inbound agency ID prop changes', async () => { const container = mount(); + await container.instance().request.promise; + const loadDataMock = jest.fn(); container.instance().loadData = loadDataMock; @@ -60,7 +62,7 @@ describe('RecipientContainer', () => { id: '555' }); - // expect(loadDataSpy.callCount).toEqual(1); + expect(loadDataMock).toHaveBeenCalledTimes(1); expect(loadDataMock).toHaveBeenCalledWith('555', inboundProps.activeFY, 1); loadDataSpy.reset(); }); @@ -149,8 +151,8 @@ describe('RecipientContainer', () => { scope: 'all' }); - container.instance().loadData(123, 2017, 1) -; + container.instance().loadData(123, 2017, 1); + await container.instance().request.promise; expect(apiSpy.callCount).toEqual(2); From 635cf66093932a50a1b817b2b1d2c2ba9388d39e Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Tue, 1 Aug 2017 14:54:09 -0400 Subject: [PATCH 78/97] Display agencies in a normal table instead of an IBTable --- .../table/AgencyLandingTable.jsx | 95 ++++++------------- .../agencyLanding/table/HeaderCell.jsx | 23 +++++ .../agencyLanding/table/HeaderRow.jsx | 29 ++++++ .../agencyLanding/table/TableCell.jsx | 31 ++++++ .../agencyLanding/table/TableRow.jsx | 38 ++++++++ .../table/cells/AgencyLinkCell.jsx | 14 +-- .../agencyLanding/table/cells/GenericCell.jsx | 34 +++++++ .../AgencyLandingContainer-test.jsx | 2 +- .../agencyLandingReducer-test.js | 4 +- 9 files changed, 188 insertions(+), 82 deletions(-) create mode 100644 src/js/components/agencyLanding/table/HeaderCell.jsx create mode 100644 src/js/components/agencyLanding/table/HeaderRow.jsx create mode 100644 src/js/components/agencyLanding/table/TableCell.jsx create mode 100644 src/js/components/agencyLanding/table/TableRow.jsx create mode 100644 src/js/components/agencyLanding/table/cells/GenericCell.jsx diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 99a854cf4b..38fcf4605b 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -7,10 +7,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import Immutable from 'immutable'; -import IBTable from 'components/sharedComponents/IBTable/IBTable'; - -import ResultsTableGenericCell from 'components/search/table/cells/ResultsTableGenericCell'; +import HeaderRow from './HeaderRow'; +import TableRow from './TableRow'; import AgencyLinkCell from './cells/AgencyLinkCell'; +import GenericCell from './cells/GenericCell'; const propTypes = { batch: PropTypes.object, @@ -20,25 +20,7 @@ const propTypes = { visibleWidth: PropTypes.number }; -const rowHeight = 50; -// setting the table height to a partial row prevents double bottom borders and also clearly -// indicates when there's more data -const tableHeight = 12.5 * rowHeight; - export default class AgencyLandingTable extends React.PureComponent { - constructor(props) { - super(props); - - this.state = { - yPos: 0, - xPos: 0, - dataHash: null - }; - - this.rowClassName = this.rowClassName.bind(this); - this.tableScrolled = this.tableScrolled.bind(this); - } - shouldComponentUpdate(nextProps) { if (!Immutable.is(nextProps.batch, this.props.batch)) { return true; @@ -50,29 +32,6 @@ export default class AgencyLandingTable extends React.PureComponent { return false; } - tableScrolled(xPos, yPos) { - // save the scroll position - this.setState({ xPos, yPos }); - } - - rowAtYPosition(yPos, returnTop = false) { - // determine the table position - let yPosition = yPos; - if (!returnTop) { - // return the bottom row - yPosition += tableHeight; - } - return Math.floor(yPosition / rowHeight); - } - - rowClassName(index) { - let evenOdd = 'odd'; - if ((index + 1) % 2 === 0) { - evenOdd = 'even'; - } - return `agency-landing-results-row-${evenOdd}`; - } - prepareTable() { let totalWidth = 0; @@ -82,7 +41,6 @@ export default class AgencyLandingTable extends React.PureComponent { // For this table, make each column's width a percentage of the visible width const adjustedWidth = (this.props.visibleWidth * column.width); totalWidth += adjustedWidth; - const isLast = i === this.props.columns.length - 1; let cellName = null; if (column.columnName === 'agency_name') { cellName = (index) => ( @@ -91,33 +49,27 @@ export default class AgencyLandingTable extends React.PureComponent { rowIndex={index} name={this.props.results[index][column.columnName]} id={this.props.results[index].agency_id} - dataHash={this.state.dataHash} - column={column.columnName} - isLastColumn={isLast} /> + column={column.columnName} /> ); } else { cellName = (index) => ( - + column={column.columnName} /> ); } return { width: adjustedWidth, name: column.columnName, columnId: `${column.columnName}`, - rowClassName: this.rowClassName, header: ( + defaultDirection={column.defaultDirection} /> ), cell: cellName }; @@ -138,19 +90,30 @@ export default class AgencyLandingTable extends React.PureComponent { noResultsClass = ' no-results'; } + const rowCount = this.props.results.length; + const rows = []; + for (let i = 0; i <= (rowCount - 1); i++) { + const row = (); + rows.push(row); + } + return (
    - + + + + + + {rows} + +
    ); } diff --git a/src/js/components/agencyLanding/table/HeaderCell.jsx b/src/js/components/agencyLanding/table/HeaderCell.jsx new file mode 100644 index 0000000000..22ca0857dd --- /dev/null +++ b/src/js/components/agencyLanding/table/HeaderCell.jsx @@ -0,0 +1,23 @@ +/** + * HeaderCell.jsx + * Created by Lizzie Salita 08/01/17 + **/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +const propTypes = { + header: PropTypes.node +}; + +export default class HeaderCell extends React.Component { + render() { + return ( + + {this.props.header} + + ); + } +} + +HeaderCell.propTypes = propTypes; diff --git a/src/js/components/agencyLanding/table/HeaderRow.jsx b/src/js/components/agencyLanding/table/HeaderRow.jsx new file mode 100644 index 0000000000..fe6df68e1f --- /dev/null +++ b/src/js/components/agencyLanding/table/HeaderRow.jsx @@ -0,0 +1,29 @@ +/** + * HeaderRow.jsx + * Created by Lizzie Salita 08/01/17 + **/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +import HeaderCell from './HeaderCell'; + +const propTypes = { + columns: PropTypes.array +}; + +export default class HeaderRow extends React.Component { + render() { + const headers = this.props.columns.map((column) => ( + + )); + + return ( + + {headers} + + ); + } +} + +HeaderRow.propTypes = propTypes; diff --git a/src/js/components/agencyLanding/table/TableCell.jsx b/src/js/components/agencyLanding/table/TableCell.jsx new file mode 100644 index 0000000000..a69a1fbea3 --- /dev/null +++ b/src/js/components/agencyLanding/table/TableCell.jsx @@ -0,0 +1,31 @@ +/** + * TableCell.jsx + * Created by Lizzie Salita 08/01/17 + **/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +const propTypes = { + rowIndex: PropTypes.number, + column: PropTypes.object +}; + +export default class TableCell extends React.Component { + render() { + let rowClass = 'row-even'; + if (this.props.rowIndex % 2 === 0) { + // row index is zero-based + rowClass = 'row-odd'; + } + + return ( + + {this.props.column.cell(this.props.rowIndex)} + + ); + } +} + +TableCell.propTypes = propTypes; + diff --git a/src/js/components/agencyLanding/table/TableRow.jsx b/src/js/components/agencyLanding/table/TableRow.jsx new file mode 100644 index 0000000000..eab0bcf597 --- /dev/null +++ b/src/js/components/agencyLanding/table/TableRow.jsx @@ -0,0 +1,38 @@ +/** + * TableRow.jsx + * Created by Lizzie Salita 08/01/17 + **/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import TableCell from './TableCell'; + +const propTypes = { + columns: PropTypes.array.isRequired, + dataHash: PropTypes.string, + rowIndex: PropTypes.number.isRequired +}; + +export default class TableRow extends React.PureComponent { + shouldComponentUpdate(nextProps) { + // force an update if the data hash has changed + return (nextProps.dataHash !== this.props.dataHash); + } + + render() { + const cells = this.props.columns.map((column) => ( + + )); + + return ( + + {cells} + + ); + } +} + +TableRow.propTypes = propTypes; diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx index 126ee9f00b..cafe9faf1e 100644 --- a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -10,19 +10,11 @@ const propTypes = { name: PropTypes.array, rowIndex: PropTypes.number, column: PropTypes.string, - isLastColumn: PropTypes.bool, id: PropTypes.number }; export default class AgencyLinkCell extends React.Component { render() { - // cell needs to have some content or it will collapse - // replace with a   if there's no data - let content = this.props.name; - if (!content) { - content = "\u00A0"; - } - // calculate even-odd class names let rowClass = 'row-even'; if (this.props.rowIndex % 2 === 0) { @@ -30,12 +22,8 @@ export default class AgencyLinkCell extends React.Component { rowClass = 'row-odd'; } - if (this.props.isLastColumn) { - rowClass += ' last-column'; - } - return ( -
    +
    {this.props.name} diff --git a/src/js/components/agencyLanding/table/cells/GenericCell.jsx b/src/js/components/agencyLanding/table/cells/GenericCell.jsx new file mode 100644 index 0000000000..fc684b6452 --- /dev/null +++ b/src/js/components/agencyLanding/table/cells/GenericCell.jsx @@ -0,0 +1,34 @@ +/** + * GenericCell.jsx + * Created by Lizzie Salita 08/01/17 + **/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +const propTypes = { + data: PropTypes.string, + rowIndex: PropTypes.number, + column: PropTypes.string +}; + +export default class ResultsTableGenericCell extends React.Component { + render() { + // calculate even-odd class names + let rowClass = 'row-even'; + if (this.props.rowIndex % 2 === 0) { + // row index is zero-based + rowClass = 'row-odd'; + } + + return ( +
    +
    + {this.props.data} +
    +
    + ); + } +} + +ResultsTableGenericCell.propTypes = propTypes; diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index 73f9848640..8d29065d24 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -79,7 +79,7 @@ describe('AgencyLandingContainer', () => { columns: [ { columnName: "agency_name", - defaultDirection: "desc", + defaultDirection: "asc", displayName: "Agency Name", width: 0.35 }, diff --git a/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js b/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js index 5bf925ca60..8130709fe2 100644 --- a/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js +++ b/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js @@ -11,7 +11,7 @@ describe('agencyLandingReducer', () => { it('should add Agency objects to the Redux store', () => { let state = agencyLandingReducer(initialState, {}); - const model = new Immutable.OrderedSet([ + const model = [ new Agency({ agency_id: 1, agency_name: 'Test 1', @@ -24,7 +24,7 @@ describe('agencyLandingReducer', () => { budget_authority_amount: '2345678', percentage_of_total_budget_authority: '0.023' }) - ]); + ]; const action = { type: 'SET_AGENCIES', agencies: model From 57d887d641f9223d30eec4a58526538ce86eaf28 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Tue, 1 Aug 2017 16:05:22 -0400 Subject: [PATCH 79/97] Fix IE filter removal icon bug, standardize top filter bar behavior with sidebar filter items --- .../elements/filters/_selectedFilterBtn.scss | 1 + src/_scss/pages/search/topFilterBar/_tag.scss | 17 ++++++++++++----- .../search/topFilterBar/TopFilterItem.jsx | 16 ++++++++-------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/_scss/elements/filters/_selectedFilterBtn.scss b/src/_scss/elements/filters/_selectedFilterBtn.scss index e17aa7cca7..9a181b9d7f 100644 --- a/src/_scss/elements/filters/_selectedFilterBtn.scss +++ b/src/_scss/elements/filters/_selectedFilterBtn.scss @@ -28,6 +28,7 @@ vertical-align: middle; & svg { width: rem(8); + height: rem(8); fill: $color-gray; } } diff --git a/src/_scss/pages/search/topFilterBar/_tag.scss b/src/_scss/pages/search/topFilterBar/_tag.scss index bd58dd5f58..b8b722d4e6 100644 --- a/src/_scss/pages/search/topFilterBar/_tag.scss +++ b/src/_scss/pages/search/topFilterBar/_tag.scss @@ -3,6 +3,7 @@ margin-right: 6px; .filter-item { + @include button-unstyled(); display: table; margin-top: 0.5rem; margin-bottom: 0.5rem; @@ -12,9 +13,16 @@ @include border-top-radius(4px); @include border-bottom-radius(4px); + font-size: $smallest-font-size; + + &:hover, &:active { + background-color: $color-white; + } + .filter-item-title { color: $color-gray; display: table-cell; + vertical-align: middle; } .filter-item-remove-container { @@ -22,15 +30,14 @@ vertical-align: middle; .filter-remove { - @include button-unstyled(); margin-left: 10px; - width: 10px; - height: 14px; + width: rem(8); + height: rem(8); .close-icon { svg { - height: 8px; - width: 8px; + height: rem(8); + width: rem(8); fill: $color-gray; } } diff --git a/src/js/components/search/topFilterBar/TopFilterItem.jsx b/src/js/components/search/topFilterBar/TopFilterItem.jsx index b9f6c5363e..6f4d76e6c6 100644 --- a/src/js/components/search/topFilterBar/TopFilterItem.jsx +++ b/src/js/components/search/topFilterBar/TopFilterItem.jsx @@ -33,25 +33,25 @@ export default class TopFilterItem extends React.Component { return (
    -
    + +
    -
    +
    ); } From 4cbff92a5a5fd8801d63f09ffc495b4b27ecb16b Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Tue, 1 Aug 2017 16:54:22 -0400 Subject: [PATCH 80/97] Update styling to reflect new table layout --- .../table/cells/_agencyLandingCell.scss | 19 ---- .../table/cells/_agencyLandingHeaderCell.scss | 1 - .../pages/agencyLanding/table/table.scss | 90 +++++++++---------- 3 files changed, 42 insertions(+), 68 deletions(-) delete mode 100644 src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss diff --git a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss deleted file mode 100644 index 171bd2ad85..0000000000 --- a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingCell.scss +++ /dev/null @@ -1,19 +0,0 @@ -@mixin agencyLandingCell() { - .cell-content { - padding: rem(12) rem(16); - color: $color-base; - box-sizing: border-box; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-size: rem(16); - line-height: 23px; - float: right; - a { - span { - text-decoration: underline; - font-weight: 600; - } - } - } -} \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss index 4aa83dffae..18f33aeced 100644 --- a/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss +++ b/src/_scss/pages/agencyLanding/table/cells/_agencyLandingHeaderCell.scss @@ -7,7 +7,6 @@ line-height: 25px; color: $color-base; cursor: pointer; - float: right; .header-sort { display: table; diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss index b89ec9e3a4..dd2aca230c 100644 --- a/src/_scss/pages/agencyLanding/table/table.scss +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -1,54 +1,48 @@ .agency-landing-results-table { - // implement the library style - @import '../../../lib/ibTable/ibTable'; - margin-top: rem(15); display: block; &.no-results { border: none; } - .award-result-generic-cell { - @import "./cells/_agencyLandingCell"; - @include agencyLandingCell(); - &.agency-link-cell { - .cell-content { - float: left; - } - } - } - .award-result-header-cell { - @import "./cells/_agencyLandingHeaderCell"; - @include agencyLandingHeader(); - } - // gray out even rows - .row-even { - background-color: #f7f7f7; - } - - .ibt-table-container { - // override the header style - .ibt-header { - border-bottom: 1px solid #ADAFB4; - .ibt-header-cell { - background-color: $color-white; - &:first-child { - .award-result-header-cell { - .cell-content { - float: left; - } - } - } - } - } - // placeholder background for when the user scrolls really fast, with wider strips to match larger row height - .ibt-table-body-container { - .ibt-table-body { - background: repeating-linear-gradient( - $color-white, - $color-white 50px, - #f7f7f7 50px, - #f7f7f7 100px - ); - } - } - } + table { + margin-top: rem(15); + thead { + tr { + border-bottom: solid 1px $color-gray-lighter; + td { + border: 0; + } + } + .award-result-header-cell { + @import "./cells/_agencyLandingHeaderCell"; + @include agencyLandingHeader(); + } + } + tbody { + tr { + td { + border: 0; + } + .generic-cell { + .cell-content { + float: right; + } + } + .agency-link-cell { + .cell-content { + float: left; + a { + span { + text-decoration: underline; + font-weight: 600; + } + } + } + } + // gray out even rows + .row-even { + background-color: #f7f7f7; + } + } + } + } } \ No newline at end of file From 27522952e8db88c591139da73eb8a8c6717369ce Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Tue, 1 Aug 2017 18:02:32 -0400 Subject: [PATCH 81/97] Fixed a bug causing to the search bar container to search within already narrowed-down results when the input was modified --- .../table/AgencyLandingTable.jsx | 2 +- .../agencyLanding/AgencyLandingContainer.jsx | 79 +++++++++---------- .../AgencyLandingSearchBarContainer.jsx | 17 +++- .../AgencyLandingSearchBarContainer-test.jsx | 21 ++++- 4 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 38fcf4605b..00fbcf6408 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -37,7 +37,7 @@ export default class AgencyLandingTable extends React.PureComponent { const HeaderCell = this.props.headerCellClass; - const columns = this.props.columns.map((column, i) => { + const columns = this.props.columns.map((column) => { // For this table, make each column's width a percentage of the visible width const adjustedWidth = (this.props.visibleWidth * column.width); totalWidth += adjustedWidth; diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 3efbea7dca..eeb9a08242 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -10,8 +10,6 @@ import { connect } from 'react-redux'; import { isCancel } from 'axios'; import Immutable from 'immutable'; -import reactStringReplace from 'react-string-replace'; - import AgenciesTableFields from 'dataMapping/agencyLanding/agenciesTableFields'; import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; @@ -149,57 +147,54 @@ export class AgencyLandingContainer extends React.Component { parseAgencies(data) { const agencies = []; - const showAllAgencies = this.props.autocompleteAgencies.length === 0 - && !this.state.noResults; data.results.forEach((item) => { - // If there is no search term, show all agencies. - // Otherwise, only show agencies that match the search input. - if (showAllAgencies || - (this.props.autocompleteAgencies.indexOf(parseFloat(item.agency_id)) > -1)) { - // Create a link to the agency's profile page - let linkText = [item.agency_name]; - - // If the user has entered a search term, highlight the matched substring - if (this.state.agencySearchString) { - linkText = reactStringReplace(item.agency_name, this.state.agencySearchString, (match, i) => ( - {match} - )); - } + // Format budget authority amount + const formattedCurrency = + MoneyFormatter.formatMoneyWithPrecision(item.budget_authority_amount, 0); - // Format budget authority amount - const formattedCurrency = - MoneyFormatter.formatMoneyWithPrecision(item.budget_authority_amount, 0); + // Convert from decimal value to percentage + const percentage = item.percentage_of_total_budget_authority * 100; + // Round percentage to 2 decimal places + let percent = Math.round(parseFloat(percentage) * 100) / 100; - // Convert from decimal value to percentage - const percentage = item.percentage_of_total_budget_authority * 100; - // Round percentage to 2 decimal places - let percent = Math.round(parseFloat(percentage) * 100) / 100; - - if (percent === 0.00) { - percent = 'Less than 0.01%'; - } - else { - percent = `${percent}%`; - } + if (percent === 0.00) { + percent = 'Less than 0.01%'; + } + else { + percent = `${percent}%`; + } - const agencyObject = { - agency_id: item.agency_id, - agency_name: linkText, - budget_authority_amount: formattedCurrency, - percentage_of_total_budget_authority: percent - }; + const agencyObject = { + agency_id: item.agency_id, + agency_name: item.agency_name, + budget_authority_amount: formattedCurrency, + percentage_of_total_budget_authority: percent + }; - const agency = new Agency(agencyObject); - agencies.push(agency); - } + const agency = new Agency(agencyObject); + agencies.push(agency); }); this.props.setAgencies(agencies); } render() { - const resultsCount = this.props.agencies.toArray().length; + let results = []; + + if (!this.state.noResults) { + // There are results + if (this.props.autocompleteAgencies.length === 0) { + // There is no search input + results = this.props.agencies.toArray(); + } + else { + // There are agencies matching the search input + results = this.props.autocompleteAgencies; + } + } + + const resultsCount = results.length; let resultsText = `${resultsCount} results`; if (resultsCount === 1) { resultsText = `${resultsCount} result`; @@ -221,7 +216,7 @@ export class AgencyLandingContainer extends React.Component {
    diff --git a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx index a69fd4229f..11aaf82223 100644 --- a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx @@ -9,6 +9,7 @@ import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { Search } from 'js-search'; import Immutable from 'immutable'; +import reactStringReplace from 'react-string-replace'; import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; @@ -86,17 +87,25 @@ export class AgencyLandingSearchBarContainer extends React.Component { // Use the JS search library to search within the records const results = search.search(this.state.agencySearchString); - const matchedAgencyIds = []; + const matchedAgencies = []; results.forEach((item) => { - matchedAgencyIds.push(item.agency_id); + // highlight the matched substring + const updatedName = reactStringReplace(item.agency_name, this.state.agencySearchString, (match, i) => ( + {match} + )); + const updatedItem = Object.assign({}, item, { + agency_name: updatedName + }); + + matchedAgencies.push(updatedItem); }); // Add search results to Redux this.props.setAutocompleteAgencies( - matchedAgencyIds + matchedAgencies ); - this.props.setNoResults(matchedAgencyIds.length === 0); + this.props.setNoResults(matchedAgencies.length === 0); } else { this.props.setNoResults(false); diff --git a/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx index ec793b27da..122f0b249c 100644 --- a/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx @@ -7,6 +7,7 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; import Immutable from 'immutable'; +import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; import { AgencyLandingSearchBarContainer } from 'containers/agencyLanding/AgencyLandingSearchBarContainer'; @@ -175,12 +176,26 @@ describe('AgencyLandingSearchBarContainer', () => { it('should populate Agencies with matching results after performing the search', () => { // Setup redux state - // Only id's 1 & 3 have agency names with the substring we are using - const reduxState = [1, 3]; + // Only Agencies 1 & 3 have agency names with the substring we are using + const reduxState = [ + new Agency({ + "agency_id": 1, + "agency_name": ["", Agen, "cy 1"], + "budget_authority_amount": "1234567", + "percentage_of_total_budget_authority": "0.01211" + }).toJS(), + new Agency({ + "agency_id": 3, + "agency_name": ["", Agen, "cy 3"], + "budget_authority_amount": "2345678", + "percentage_of_total_budget_authority": "0.02322" + }).toJS() + ]; // setup mock redux actions for handling search results const mockReduxAction = jest.fn((args) => { - expect(args).toEqual(reduxState); + expect(args[0].agency_id).toEqual(1); + expect(args[1].agency_id).toEqual(3); }); // setup the agency list container and call the function to type a single letter From 535d91f38499f6d953ec1c9df25ce40cd8c2f739 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Wed, 2 Aug 2017 09:49:39 -0400 Subject: [PATCH 82/97] updated tests --- .../agencyLanding/AgencyLandingContainer-test.jsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index 8d29065d24..410ee95905 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -24,6 +24,7 @@ jest.mock('helpers/agencyLandingHelper', () => require('./agencyLandingHelper')) jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; const setup = (props) => shallow(); +const setupMount = (props) => mount(); // spy on specific functions inside the component const fetchAgenciesSpy = sinon.spy(AgencyLandingContainer.prototype, 'fetchAgencies'); @@ -37,7 +38,7 @@ describe('AgencyLandingContainer', () => { it('should make an API request on mount', async () => { // mount the container - const container = setup({ + const container = setupMount({ agencies: new Immutable.OrderedSet([]), agenciesOrder: mockAgenciesOrder, meta: mockMeta, @@ -57,10 +58,6 @@ describe('AgencyLandingContainer', () => { parseAgenciesSpy.reset(); }); - it('should make an API requeset when the sort order changes', async () => { - - }); - describe('showColumns', () => { it('should build the table', async () => { // mount the container @@ -108,17 +105,17 @@ describe('AgencyLandingContainer', () => { }); describe('parseAgencies', () => { - it('should parse the API response and overwrite the Redux agencies', (done) => { + it('should parse the API response and overwrite the Redux agencies', () => { const expected = Object.assign({},new Immutable.OrderedSet([ new Agency({ agency_id: 1, - agency_name: ['Agency 1'], + agency_name: 'Agency 1', budget_authority_amount: "$1,234,567", percentage_of_total_budget_authority: "1.21%" }), new Agency({ agency_id: 2, - agency_name: ['Agency 2'], + agency_name: 'Agency 2', budget_authority_amount: "$2,345,678", percentage_of_total_budget_authority: "2.32%" }) @@ -131,7 +128,6 @@ describe('AgencyLandingContainer', () => { //delete model._jsid; expect(model).toEqual(expected); - done(); }); const container = setup({ From fd006ccf6919e903a2f3ed8684c22b113224c087 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Wed, 2 Aug 2017 12:14:17 -0400 Subject: [PATCH 83/97] Fixes: changed default sort order, removed first sentence of intro paragraph, moved HTML from container into a new component, made agency name prop type consistent --- .../pages/agencyLanding/table/table.scss | 8 +++ .../agencyLanding/AgencyLandingContent.jsx | 55 +++++++++++++++++++ .../agencyLanding/AgencyLandingPage.jsx | 7 +-- .../agencyLanding/AgencyLandingContainer.jsx | 35 ++++-------- .../agencyLanding/agencyLandingReducer.js | 4 +- .../AgencyLandingContainer-test.jsx | 13 ++--- 6 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 src/js/components/agencyLanding/AgencyLandingContent.jsx diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss index dd2aca230c..fee7cfb17f 100644 --- a/src/_scss/pages/agencyLanding/table/table.scss +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -10,6 +10,14 @@ border-bottom: solid 1px $color-gray-lighter; td { border: 0; + .cell-content { + float: right; + } + &:first-child { + .cell-content { + float: left; + } + } } } .award-result-header-cell { diff --git a/src/js/components/agencyLanding/AgencyLandingContent.jsx b/src/js/components/agencyLanding/AgencyLandingContent.jsx new file mode 100644 index 0000000000..06c7a1a68a --- /dev/null +++ b/src/js/components/agencyLanding/AgencyLandingContent.jsx @@ -0,0 +1,55 @@ +/** + * AgencyLandingContent.jsx + * Created by Lizzie Salita 8/02/17 + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import Immutable from 'immutable'; + +import AgencyLandingSearchBarContainer from 'containers/agencyLanding/AgencyLandingSearchBarContainer'; +import AgencyLandingResultsSection from './AgencyLandingResultsSection'; + +const propTypes = { + resultsText: PropTypes.string, + results: PropTypes.array, + agencySearchString: PropTypes.string, + inFlight: PropTypes.bool, + columns: PropTypes.array, + setAgencySearchString: PropTypes.func, + setNoResults: PropTypes.func, + agencies: PropTypes.instanceOf(Immutable.OrderedSet), + agenciesOrder: PropTypes.object, + setAgencies: PropTypes.func, + meta: PropTypes.object, + autocompleteAgencies: PropTypes.array +}; + +export default class AgencyLandingContent extends React.Component { + render() { + return ( +
    +
    +
    + +
    +
    +
    + {this.props.resultsText} +
    +
    + +
    +
    + ); + } +} + +AgencyLandingContent.propTypes = propTypes; diff --git a/src/js/components/agencyLanding/AgencyLandingPage.jsx b/src/js/components/agencyLanding/AgencyLandingPage.jsx index df18cc7143..4e1f53a59e 100644 --- a/src/js/components/agencyLanding/AgencyLandingPage.jsx +++ b/src/js/components/agencyLanding/AgencyLandingPage.jsx @@ -27,10 +27,9 @@ export default class AgencyLandingPage extends React.Component {

    Find an Agency Profile.

    Understand the current spending of agencies in our agency profiles.
    -

    Sixty-six federal agencies report data to USAspending.gov. These include the - 15 executive departments whose leaders sit on the President's Cabinet, as well - as small independent boards and commissions. They range in size from $700 billion - down to less than $200,000.

    +

    These include the 15 executive departments whose leaders sit on the + President's Cabinet, as well as small independent boards and + commissions. They range in size from $700 billion down to less than $200,000.

    diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index eeb9a08242..08ccfd43b7 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -16,8 +16,7 @@ import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; import * as AgencyLandingHelper from 'helpers/agencyLandingHelper'; import * as MoneyFormatter from 'helpers/moneyFormatter'; -import AgencyLandingResultsSection from 'components/agencyLanding/AgencyLandingResultsSection'; -import AgencyLandingSearchBarContainer from './AgencyLandingSearchBarContainer'; +import AgencyLandingContent from 'components/agencyLanding/AgencyLandingContent'; const propTypes = { agencies: PropTypes.instanceOf(Immutable.OrderedSet), @@ -54,6 +53,7 @@ export class AgencyLandingContainer extends React.Component { // table sort changed this.fetchAgencies(); } + // TODO- Lizzie: update lifecycle / don't make an API call here if (this.props.autocompleteAgencies !== prevProps.autocompleteAgencies) { // search input changed this.fetchAgencies(); @@ -167,7 +167,7 @@ export class AgencyLandingContainer extends React.Component { const agencyObject = { agency_id: item.agency_id, - agency_name: item.agency_name, + agency_name: [item.agency_name], budget_authority_amount: formattedCurrency, percentage_of_total_budget_authority: percent }; @@ -201,26 +201,15 @@ export class AgencyLandingContainer extends React.Component { } return ( -
    -
    -
    - -
    -
    -
    - {resultsText} -
    -
    - -
    -
    + ); } } diff --git a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js index 7107fa3cba..b3d88815ae 100644 --- a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js +++ b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js @@ -16,8 +16,8 @@ export const Agency = Record({ const initialState = { agencies: new OrderedSet(), agenciesOrder: { - field: 'agency_name', - direction: 'asc' + field: 'percentage_of_total_budget_authority', + direction: 'desc' }, agenciesMeta: { batch: { diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index 410ee95905..c925ccd5e2 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -11,10 +11,8 @@ import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; import { AgencyLandingContainer } from 'containers/agencyLanding/AgencyLandingContainer'; -import { AgencyLandingSearchBarContainer } from - 'containers/agencyLanding/AgencyLandingSearchBarContainer'; -import AgencyLandingResultsSection from - 'components/agencyLanding/AgencyLandingResultsSection'; +import AgencyLandingContent from + 'components/agencyLanding/AgencyLandingContent'; import { mockComponent, unmockComponent } from '../../testResources/mockComponent'; @@ -32,8 +30,7 @@ const parseAgenciesSpy = sinon.spy(AgencyLandingContainer.prototype, 'parseAgenc describe('AgencyLandingContainer', () => { beforeAll(() => { - mockComponent(AgencyLandingResultsSection); - mockComponent(AgencyLandingSearchBarContainer); + mockComponent(AgencyLandingContent); }); it('should make an API request on mount', async () => { @@ -109,13 +106,13 @@ describe('AgencyLandingContainer', () => { const expected = Object.assign({},new Immutable.OrderedSet([ new Agency({ agency_id: 1, - agency_name: 'Agency 1', + agency_name: ['Agency 1'], budget_authority_amount: "$1,234,567", percentage_of_total_budget_authority: "1.21%" }), new Agency({ agency_id: 2, - agency_name: 'Agency 2', + agency_name: ['Agency 2'], budget_authority_amount: "$2,345,678", percentage_of_total_budget_authority: "2.32%" }) From 82e805cb878ab361e41b3707eb1e5bb17ddb7591 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Wed, 2 Aug 2017 13:34:14 -0400 Subject: [PATCH 84/97] Eliminated unnecessary API call that was made when the search input changed --- src/js/components/agencyLanding/AgencyLandingContent.jsx | 2 ++ .../agencyLanding/AgencyLandingResultsSection.jsx | 3 ++- .../agencyLanding/table/AgencyLandingTable.jsx | 8 ++++++-- .../containers/agencyLanding/AgencyLandingContainer.jsx | 9 ++++----- .../agencyLanding/AgencyLandingContainer-test.jsx | 3 --- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/js/components/agencyLanding/AgencyLandingContent.jsx b/src/js/components/agencyLanding/AgencyLandingContent.jsx index 06c7a1a68a..bcf38244f7 100644 --- a/src/js/components/agencyLanding/AgencyLandingContent.jsx +++ b/src/js/components/agencyLanding/AgencyLandingContent.jsx @@ -13,6 +13,7 @@ import AgencyLandingResultsSection from './AgencyLandingResultsSection'; const propTypes = { resultsText: PropTypes.string, results: PropTypes.array, + searchHash: PropTypes.number, agencySearchString: PropTypes.string, inFlight: PropTypes.bool, columns: PropTypes.array, @@ -42,6 +43,7 @@ export default class AgencyLandingContent extends React.Component {
    ); diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index 08ccfd43b7..c96887cbe2 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -53,11 +53,6 @@ export class AgencyLandingContainer extends React.Component { // table sort changed this.fetchAgencies(); } - // TODO- Lizzie: update lifecycle / don't make an API call here - if (this.props.autocompleteAgencies !== prevProps.autocompleteAgencies) { - // search input changed - this.fetchAgencies(); - } } componentWillUnmount() { @@ -200,11 +195,15 @@ export class AgencyLandingContainer extends React.Component { resultsText = `${resultsCount} result`; } + // Create an Ordered Set for the search hash + const autocompleteSet = new Immutable.OrderedSet(this.props.autocompleteAgencies); + return ( { autocompleteAgencies: [] }); - // componentDidMount doesn't get called automatically with shallow - container.instance().showColumns(); - await container.instance().agenciesRequest.promise; expect(fetchAgenciesSpy.callCount).toEqual(1); From 3665620bb3bc4a96283d80ea946cba39f216df77 Mon Sep 17 00:00:00 2001 From: Emily Gullo Date: Thu, 3 Aug 2017 10:28:30 -0400 Subject: [PATCH 85/97] Update to text size and margins to bring them in line with other filters --- src/_scss/pages/search/filters/otherFilters/otherFilters.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/_scss/pages/search/filters/otherFilters/otherFilters.scss b/src/_scss/pages/search/filters/otherFilters/otherFilters.scss index b8632a5753..c197352759 100644 --- a/src/_scss/pages/search/filters/otherFilters/otherFilters.scss +++ b/src/_scss/pages/search/filters/otherFilters/otherFilters.scss @@ -6,8 +6,10 @@ .filter-item-wrap { p { - margin-top: rem(5); + font-size: rem(14); + line-height: rem(15); margin-bottom: rem(5); + margin-top: rem(0); } } .shown { From 207e6a3449d058809f30a2c68a15940235bdbd10 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 3 Aug 2017 11:55:28 -0400 Subject: [PATCH 86/97] Styling updates: large screen gutter, mobile search bar --- .../layouts/landingPage/landingPage.scss | 30 ++++++++++++++++ .../agencyLanding/agencyLandingPage.scss | 36 +++++-------------- .../agencyLanding/agencyLandingSearch.scss | 35 ++++++++++++------ .../agencyLanding/AgencyLandingContent.jsx | 23 +++++++----- .../agencyLanding/AgencyLandingPage.jsx | 11 +----- .../agencyLanding/AgencyLandingSearchBar.jsx | 2 +- .../table/AgencyLandingTable.jsx | 2 +- .../agencyLanding/table/cells/GenericCell.jsx | 9 +---- 8 files changed, 82 insertions(+), 66 deletions(-) create mode 100644 src/_scss/layouts/landingPage/landingPage.scss diff --git a/src/_scss/layouts/landingPage/landingPage.scss b/src/_scss/layouts/landingPage/landingPage.scss new file mode 100644 index 0000000000..0c182ae347 --- /dev/null +++ b/src/_scss/layouts/landingPage/landingPage.scss @@ -0,0 +1,30 @@ +@import "../default/default"; +@import "../summary/summary"; +@import "mixins/fullSectionWrap"; + +.landing-page-content { + padding: $global-pad; + .landing-page-overview { + @include span-columns(16); + @include shift(0); + + text-align: center; + h3 { + margin-top: 0; + } + p { + color: $color-gray-medium; + margin-bottom: rem(30); + } + } + .landing-page-section { + @include span-columns(16); + } + @include media($medium-screen) { + padding: ($global-pad * 2); + .landing-page-overview { + @include span-columns(12); + @include shift(2); + } + } +} diff --git a/src/_scss/pages/agencyLanding/agencyLandingPage.scss b/src/_scss/pages/agencyLanding/agencyLandingPage.scss index b8138235f1..83eb8e4da9 100644 --- a/src/_scss/pages/agencyLanding/agencyLandingPage.scss +++ b/src/_scss/pages/agencyLanding/agencyLandingPage.scss @@ -1,35 +1,17 @@ .usa-da-agency-landing { - @import "layouts/summary/summary"; - @import "mixins/fullSectionWrap"; + @import "layouts/landingPage/landingPage"; @import "./header/header"; @import './agencyLandingSearch'; @import './table/resultsSection'; - .agency-landing-content { - padding: ($global-pad * 2) 0; - .agency-landing-overview { - @include span-columns(12); - @include shift(2); - text-align: center; - h3 { - margin-top: 0; - } - p { - color: $color-gray-medium; - margin-bottom: rem(30); - } - } - .agency-landing-container { - .agency-landing-section { - @include fullSectionWrap(0,0); - &.results-count { - font-style: italic; - padding: rem(20) 0; - font-size: rem(16); - } - } - @include agencyLandingSearch; - @include resultsSection; + .landing-page-section { + &.results-count { + font-style: italic; + padding: rem(20) 0; + font-size: rem(16); } } + @include agencyLandingSearch; + @include resultsSection; + } \ No newline at end of file diff --git a/src/_scss/pages/agencyLanding/agencyLandingSearch.scss b/src/_scss/pages/agencyLanding/agencyLandingSearch.scss index b277ab836a..5d21c8b6d2 100644 --- a/src/_scss/pages/agencyLanding/agencyLandingSearch.scss +++ b/src/_scss/pages/agencyLanding/agencyLandingSearch.scss @@ -2,34 +2,49 @@ .agency-landing-search { @include span-columns(16); background-color: $color-primary-alt-lightest; - padding: rem(30); + padding: rem(5); border: 1px solid $color-vis-lightest; text-align: center; form { - // TODO - Lizzie: add mobile styling position: relative; input.search-field { color: $color-gray-light; - font-size: rem(28); + font-size: rem(14); font-weight: 300; line-height: rem(36); - padding: rem(15); - width: 75%; - padding-right: rem(30); + padding: 0 rem(30) 0 rem(4); + width: 100%; } .search-button { position: absolute; - left: 80%; - top: rem(15); + top: rem(5); + left: 90%; @include button-unstyled; - width: 36px; - height: 36px; + width: 25px; + height: 25px; svg { fill: $color-gray-light; } } } + @include media($medium-screen) { + padding: rem(30); + form { + input.search-field { + width: 75%; + font-size: rem(28); + padding: rem(15); + padding-right: rem(30); + } + .search-button { + left: 80%; + top: rem(15); + width: 36px; + height: 36px; + } + } + } } } \ No newline at end of file diff --git a/src/js/components/agencyLanding/AgencyLandingContent.jsx b/src/js/components/agencyLanding/AgencyLandingContent.jsx index bcf38244f7..a6a806ede0 100644 --- a/src/js/components/agencyLanding/AgencyLandingContent.jsx +++ b/src/js/components/agencyLanding/AgencyLandingContent.jsx @@ -29,18 +29,23 @@ const propTypes = { export default class AgencyLandingContent extends React.Component { render() { return ( -
    -
    -
    - -
    +
    +
    +

    Find an Agency Profile.

    +
    Understand the current spending of agencies in our agency profiles.
    +

    These include the 15 executive departments whose leaders sit on the + President's Cabinet, as well as small independent boards and + commissions. They range in size from $700 billion down to less than $200,000.

    -
    +
    + +
    +
    {this.props.resultsText}
    -
    +
    -
    -
    -

    Find an Agency Profile.

    -
    Understand the current spending of agencies in our agency profiles.
    -

    These include the 15 executive departments whose leaders sit on the - President's Cabinet, as well as small independent boards and - commissions. They range in size from $700 billion down to less than $200,000.

    -
    - -
    +
    diff --git a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx index 74099817bb..6868d67e0a 100644 --- a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx +++ b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx @@ -19,7 +19,7 @@ export default class AgencyLandingSearchBar extends React.Component { render() { return ( -
    +
    - +
    +
    {this.props.data}
    From 8b432b1cd5dfa5776d11f7d23fc3c06c5b34e056 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 3 Aug 2017 12:04:19 -0400 Subject: [PATCH 87/97] Include agency acronym --- .../agencyLanding/AgencyLandingContainer.jsx | 2 +- .../AgencyLandingContainer-test.jsx | 7 +++---- .../agencyLanding/mockToptierAgencies.js | 19 ++++++++++++------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index c96887cbe2..c1aea4392f 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -162,7 +162,7 @@ export class AgencyLandingContainer extends React.Component { const agencyObject = { agency_id: item.agency_id, - agency_name: [item.agency_name], + agency_name: [`${item.agency_name} (${item.abbreviation})`], budget_authority_amount: formattedCurrency, percentage_of_total_budget_authority: percent }; diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index 340db8993e..c319e1a6bc 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -103,13 +103,13 @@ describe('AgencyLandingContainer', () => { const expected = Object.assign({},new Immutable.OrderedSet([ new Agency({ agency_id: 1, - agency_name: ['Agency 1'], + agency_name: ['Agency 1 (ABC)'], budget_authority_amount: "$1,234,567", percentage_of_total_budget_authority: "1.21%" }), new Agency({ agency_id: 2, - agency_name: ['Agency 2'], + agency_name: ['Agency 2 (XYZ)'], budget_authority_amount: "$2,345,678", percentage_of_total_budget_authority: "2.32%" }) @@ -139,7 +139,6 @@ describe('AgencyLandingContainer', () => { afterAll(() => { // restore the mocked component's lifecycle functions - unmockComponent(AgencyLandingResultsSection); - unmockComponent(AgencyLandingSearchBarContainer); + unmockComponent(AgencyLandingContent); }); }); diff --git a/tests/containers/agencyLanding/mockToptierAgencies.js b/tests/containers/agencyLanding/mockToptierAgencies.js index 65e1bd0a33..b356608d7e 100644 --- a/tests/containers/agencyLanding/mockToptierAgencies.js +++ b/tests/containers/agencyLanding/mockToptierAgencies.js @@ -7,13 +7,15 @@ export const mockData = { agency_id: 1, agency_name: 'Agency 1', budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.01211' + percentage_of_total_budget_authority: '0.01211', + abbreviation: 'ABC' }, { agency_id: 2, agency_name: 'Agency 2', budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.02322' + percentage_of_total_budget_authority: '0.02322', + abbreviation: 'XYZ' } ] }; @@ -22,11 +24,11 @@ export const mockSearchResults = { results: [ { agency_id: 1, - agency_name:'Agency 1' + agency_name:'Agency 1 (ABC)' }, { agency_id: 2, - agency_name:'Agency 2' + agency_name:'Agency 2 (XYZ)' } ] }; @@ -49,7 +51,8 @@ export const mockAgencies = [ agency_id: 1, agency_name: 'Agency 1', budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.01211' + percentage_of_total_budget_authority: '0.01211', + abbreviation: 'ABC' } ), new Agency( @@ -57,7 +60,8 @@ export const mockAgencies = [ agency_id: 2, agency_name: 'Test 2', budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.02322' + percentage_of_total_budget_authority: '0.02322', + abbreviation: 'XYZ' } ), new Agency( @@ -65,7 +69,8 @@ export const mockAgencies = [ agency_id: 3, agency_name: 'Agency 3', budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.02322' + percentage_of_total_budget_authority: '0.02322', + abbreviation: 'DEF' } ) ]; From 41b5acb44d5607494db61c27f65c968b59a35de8 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 3 Aug 2017 12:36:51 -0400 Subject: [PATCH 88/97] Fix for failing test --- .../account/filters/AccountProgramActivityContainer-test.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx b/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx index 3b0df486a1..d0f3f508c8 100644 --- a/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx +++ b/tests/containers/account/filters/AccountProgramActivityContainer-test.jsx @@ -23,7 +23,7 @@ const account = { id: 2525 }; -jest.mock('helpers/searchHelper', () => require('../accountHelper')); +jest.mock('helpers/accountHelper', () => require('../accountHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; describe('AccountProgramActivityContainer', () => { From 7b6e96da599d9340ac8e4892352f0e05248050e8 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 3 Aug 2017 13:37:01 -0400 Subject: [PATCH 89/97] cursor --- src/_scss/elements/filters/_selectedFilterBtn.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_scss/elements/filters/_selectedFilterBtn.scss b/src/_scss/elements/filters/_selectedFilterBtn.scss index 9a181b9d7f..3da1d554ed 100644 --- a/src/_scss/elements/filters/_selectedFilterBtn.scss +++ b/src/_scss/elements/filters/_selectedFilterBtn.scss @@ -38,7 +38,8 @@ cursor: pointer; @include transition(all 0.25s $ease-in-out-sine); & .close { - & svg { + & svg, + & path { cursor: pointer; fill: $color-cool-blue; } From 0657da2f6d4bf1d948a438f5e02da5a86c013402 Mon Sep 17 00:00:00 2001 From: Mike Bray Date: Thu, 3 Aug 2017 13:38:06 -0400 Subject: [PATCH 90/97] Update _selectedFilterBtn.scss --- src/_scss/elements/filters/_selectedFilterBtn.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/_scss/elements/filters/_selectedFilterBtn.scss b/src/_scss/elements/filters/_selectedFilterBtn.scss index 3da1d554ed..07e35796c5 100644 --- a/src/_scss/elements/filters/_selectedFilterBtn.scss +++ b/src/_scss/elements/filters/_selectedFilterBtn.scss @@ -38,6 +38,9 @@ cursor: pointer; @include transition(all 0.25s $ease-in-out-sine); & .close { + cursor: pointer; + fill: $color-cool-blue; + & svg, & path { cursor: pointer; @@ -46,4 +49,4 @@ } } } -} \ No newline at end of file +} From 50625f3044b19742be9213c920da0cfceccb2d25 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 3 Aug 2017 14:19:26 -0400 Subject: [PATCH 91/97] Removed unnecessary logic --- .../agencyLanding/AgencyLandingContent.jsx | 6 +-- .../AgencyLandingResultsSection.jsx | 2 +- .../table/AgencyLandingTable.jsx | 2 +- .../agencyLanding/AgencyLandingContainer.jsx | 44 +++++-------------- .../AgencyLandingSearchBarContainer.jsx | 7 --- .../agencyLanding/agenciesTableFields.js | 6 --- .../AgencyLandingContainer-test.jsx | 13 ++---- 7 files changed, 18 insertions(+), 62 deletions(-) diff --git a/src/js/components/agencyLanding/AgencyLandingContent.jsx b/src/js/components/agencyLanding/AgencyLandingContent.jsx index a6a806ede0..e6f778fe06 100644 --- a/src/js/components/agencyLanding/AgencyLandingContent.jsx +++ b/src/js/components/agencyLanding/AgencyLandingContent.jsx @@ -13,12 +13,11 @@ import AgencyLandingResultsSection from './AgencyLandingResultsSection'; const propTypes = { resultsText: PropTypes.string, results: PropTypes.array, - searchHash: PropTypes.number, + searchHash: PropTypes.string, agencySearchString: PropTypes.string, inFlight: PropTypes.bool, columns: PropTypes.array, setAgencySearchString: PropTypes.func, - setNoResults: PropTypes.func, agencies: PropTypes.instanceOf(Immutable.OrderedSet), agenciesOrder: PropTypes.object, setAgencies: PropTypes.func, @@ -39,8 +38,7 @@ export default class AgencyLandingContent extends React.Component {
    + setAgencySearchString={this.props.setAgencySearchString} />
    {this.props.resultsText} diff --git a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx index a16b4f10ef..53fb2b13e3 100644 --- a/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx +++ b/src/js/components/agencyLanding/AgencyLandingResultsSection.jsx @@ -15,7 +15,7 @@ const propTypes = { results: PropTypes.array, columns: PropTypes.array, agencySearchString: PropTypes.string, - searchHash: PropTypes.number + searchHash: PropTypes.string }; export default class AgencyLandingResultsSection extends React.Component { diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index 3ba6207e50..bb4d440d3e 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -18,7 +18,7 @@ const propTypes = { columns: PropTypes.array, headerCellClass: PropTypes.func.isRequired, visibleWidth: PropTypes.number, - searchHash: PropTypes.number + searchHash: PropTypes.string }; export default class AgencyLandingTable extends React.PureComponent { diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index c1aea4392f..d04bf5cb71 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -34,14 +34,11 @@ export class AgencyLandingContainer extends React.Component { columns: [], inFlight: false, currentFY: '', - agencySearchString: '', - autocompleteAgencies: [], - noResults: false + agencySearchString: '' }; this.agenciesRequest = null; this.setAgencySearchString = this.setAgencySearchString.bind(this); - this.setNoResults = this.setNoResults.bind(this); } componentDidMount() { @@ -67,16 +64,9 @@ export class AgencyLandingContainer extends React.Component { }); } - setNoResults(noResults) { - this.setState({ - noResults - }); - } - showColumns() { const columns = []; const sortOrder = AgenciesTableFields.defaultSortDirection; - const widths = AgenciesTableFields.columnWidthPercentage; AgenciesTableFields.order.forEach((col) => { let displayName = AgenciesTableFields[col]; @@ -90,7 +80,6 @@ export class AgencyLandingContainer extends React.Component { const column = { columnName: col, displayName, - width: widths[col], defaultDirection: sortOrder[col] }; columns.push(column); @@ -148,17 +137,13 @@ export class AgencyLandingContainer extends React.Component { const formattedCurrency = MoneyFormatter.formatMoneyWithPrecision(item.budget_authority_amount, 0); - // Convert from decimal value to percentage - const percentage = item.percentage_of_total_budget_authority * 100; - // Round percentage to 2 decimal places - let percent = Math.round(parseFloat(percentage) * 100) / 100; + // Convert from decimal value to percentage and round to 2 decimal places + const percentage = (item.percentage_of_total_budget_authority * 100).toFixed(2); - if (percent === 0.00) { + let percent = `${percentage}%`; + if (percentage === 0.00) { percent = 'Less than 0.01%'; } - else { - percent = `${percent}%`; - } const agencyObject = { agency_id: item.agency_id, @@ -175,18 +160,10 @@ export class AgencyLandingContainer extends React.Component { } render() { - let results = []; + let results = this.props.agencies.toArray(); - if (!this.state.noResults) { - // There are results - if (this.props.autocompleteAgencies.length === 0) { - // There is no search input - results = this.props.agencies.toArray(); - } - else { - // There are agencies matching the search input - results = this.props.autocompleteAgencies; - } + if (this.state.agencySearchString.length > 1) { + results = this.props.autocompleteAgencies; } const resultsCount = results.length; @@ -203,12 +180,11 @@ export class AgencyLandingContainer extends React.Component { {...this.props} resultsText={resultsText} results={results} - searchHash={autocompleteSet.hashCode()} + searchHash={`${autocompleteSet.hashCode()} - ${this.state.agencySearchString}`} agencySearchString={this.state.agencySearchString} inFlight={this.state.inFlight} columns={this.state.columns} - setAgencySearchString={this.setAgencySearchString} - setNoResults={this.setNoResults} /> + setAgencySearchString={this.setAgencySearchString} /> ); } } diff --git a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx index 11aaf82223..3e0ef3ce3b 100644 --- a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx @@ -17,7 +17,6 @@ import AgencyLandingSearchBar from 'components/agencyLanding/AgencyLandingSearch const propTypes = { setAgencySearchString: PropTypes.func, - setNoResults: PropTypes.func, setAutocompleteAgencies: PropTypes.func, autocompleteAgencies: PropTypes.array, agencies: PropTypes.instanceOf(Immutable.OrderedSet) @@ -48,9 +47,6 @@ export class AgencyLandingSearchBarContainer extends React.Component { handleTextInput(agencyInput) { // Clear existing agencies this.props.setAutocompleteAgencies([]); - if (agencyInput === '') { - this.props.setNoResults(false); - } // Grab input, clear any exiting timeout const input = agencyInput.target.value; @@ -104,11 +100,8 @@ export class AgencyLandingSearchBarContainer extends React.Component { this.props.setAutocompleteAgencies( matchedAgencies ); - - this.props.setNoResults(matchedAgencies.length === 0); } else { - this.props.setNoResults(false); this.props.setAgencySearchString(''); this.setState({ agencySearchString: '' diff --git a/src/js/dataMapping/agencyLanding/agenciesTableFields.js b/src/js/dataMapping/agencyLanding/agenciesTableFields.js index ff35b03e98..b676d2cb12 100644 --- a/src/js/dataMapping/agencyLanding/agenciesTableFields.js +++ b/src/js/dataMapping/agencyLanding/agenciesTableFields.js @@ -4,12 +4,6 @@ const agenciesTableFields = { budget_authority_amount: 'desc', percentage_of_total_budget_authority: 'desc' }, - // Fraction of the visible width the column should take up - columnWidthPercentage: { - agency_name: 0.35, - budget_authority_amount: 0.3, - percentage_of_total_budget_authority: 0.35 - }, defaultSortField: 'agency_name', order: [ 'agency_name', diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index c319e1a6bc..dc958b9010 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -71,27 +71,22 @@ describe('AgencyLandingContainer', () => { { columnName: "agency_name", defaultDirection: "asc", - displayName: "Agency Name", - width: 0.35 + displayName: "Agency Name" }, { columnName: "budget_authority_amount", defaultDirection: "desc", - displayName: "Budget Authority", - width: 0.3 + displayName: "Budget Authority" }, { columnName: "percentage_of_total_budget_authority", defaultDirection: "desc", - displayName: "Percent of Total U.S. Budget", - width: 0.35 + displayName: "Percent of Total U.S. Budget" } ], inFlight: false, currentFY: '', - agencySearchString: '', - autocompleteAgencies: [], - noResults: false + agencySearchString: '' }; expect(container.state()).toEqual(expectedState); From 403dae9a49970c45cd41cdf6fbcfb44e19bda452 Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 3 Aug 2017 14:33:04 -0400 Subject: [PATCH 92/97] Added a test for sort order change --- .../AgencyLandingContainer-test.jsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index dc958b9010..b113cae9ba 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -52,6 +52,32 @@ describe('AgencyLandingContainer', () => { parseAgenciesSpy.reset(); }); + it('should make an API request when the sort order changes', async () => { + // mount the container + const container = setupMount({ + agencies: new Immutable.OrderedSet([]), + agenciesOrder: mockAgenciesOrder, + meta: mockMeta, + autocompleteAgencies: [] + }); + + await container.instance().agenciesRequest.promise; + + expect(fetchAgenciesSpy.callCount).toEqual(1); + + // change the sort order + container.setProps({ + agenciesOrder: { + sort: 'budget_authority_amount', + direction: 'asc' + } + }); + + await container.instance().agenciesRequest.promise; + + expect(fetchAgenciesSpy.callCount).toEqual(2); + }); + describe('showColumns', () => { it('should build the table', async () => { // mount the container From adc8f01176be8c79c4bb47ee439fe239eb4e3ac5 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 3 Aug 2017 16:53:55 -0400 Subject: [PATCH 93/97] Update to use local search only and limit API calls --- .../agencyLanding/AgencyLandingContent.jsx | 15 +- .../AgencyLandingResultsSection.jsx | 41 +--- .../agencyLanding/AgencyLandingSearchBar.jsx | 5 +- .../table/AgencyLandingTable.jsx | 98 +------- .../agencyLanding/table/HeaderRow.jsx | 11 +- .../agencyLanding/table/TableRow.jsx | 40 +++- .../table/cells/AgencyLinkCell.jsx | 2 +- .../agencyLanding/AgencyLandingContainer.jsx | 92 +++++--- .../AgencyLandingSearchBarContainer.jsx | 128 ---------- .../AgencyLandingHeaderCellContainer.jsx | 12 +- .../agencyLanding/agenciesTableFields.js | 4 +- .../agencyLanding/agencyLandingActions.js | 10 - .../agencyLanding/agencyLandingReducer.js | 39 +-- .../AgencyLandingContainer-test.jsx | 105 +++------ .../AgencyLandingSearchBarContainer-test.jsx | 223 ------------------ .../agencyLanding/agencyLandingHelper.js | 15 +- .../agencyLanding/mockToptierAgencies.js | 114 ++++----- .../agencyLandingReducer-test.js | 63 +---- 18 files changed, 216 insertions(+), 801 deletions(-) delete mode 100644 src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx delete mode 100644 tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx diff --git a/src/js/components/agencyLanding/AgencyLandingContent.jsx b/src/js/components/agencyLanding/AgencyLandingContent.jsx index e6f778fe06..aad52e9126 100644 --- a/src/js/components/agencyLanding/AgencyLandingContent.jsx +++ b/src/js/components/agencyLanding/AgencyLandingContent.jsx @@ -5,24 +5,17 @@ import React from 'react'; import PropTypes from 'prop-types'; -import Immutable from 'immutable'; -import AgencyLandingSearchBarContainer from 'containers/agencyLanding/AgencyLandingSearchBarContainer'; +import AgencyLandingSearchBar from './AgencyLandingSearchBar'; import AgencyLandingResultsSection from './AgencyLandingResultsSection'; const propTypes = { resultsText: PropTypes.string, results: PropTypes.array, - searchHash: PropTypes.string, agencySearchString: PropTypes.string, inFlight: PropTypes.bool, columns: PropTypes.array, - setAgencySearchString: PropTypes.func, - agencies: PropTypes.instanceOf(Immutable.OrderedSet), - agenciesOrder: PropTypes.object, - setAgencies: PropTypes.func, - meta: PropTypes.object, - autocompleteAgencies: PropTypes.array + setAgencySearchString: PropTypes.func }; export default class AgencyLandingContent extends React.Component { @@ -37,7 +30,7 @@ export default class AgencyLandingContent extends React.Component { commissions. They range in size from $700 billion down to less than $200,000.

    -
    @@ -45,8 +38,6 @@ export default class AgencyLandingContent extends React.Component {
    -
    { - // this is an empty div that scales via CSS - // the results table width will follow this div's width - this.tableWidthController = div; - }} /> + {...this.props} />
    {message}
    diff --git a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx index 6868d67e0a..fbf96048cf 100644 --- a/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx +++ b/src/js/components/agencyLanding/AgencyLandingSearchBar.jsx @@ -9,12 +9,13 @@ import PropTypes from 'prop-types'; import { Search } from 'components/sharedComponents/icons/Icons'; const propTypes = { - handleTextInput: PropTypes.func.isRequired + setAgencySearchString: PropTypes.func.isRequired }; export default class AgencyLandingSearchBar extends React.Component { onChange(e) { - this.props.handleTextInput(e); + const value = e.target.value; + this.props.setAgencySearchString(value); } render() { diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index bb4d440d3e..fc063708a1 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -5,114 +5,38 @@ import React from 'react'; import PropTypes from 'prop-types'; -import Immutable from 'immutable'; import HeaderRow from './HeaderRow'; import TableRow from './TableRow'; -import AgencyLinkCell from './cells/AgencyLinkCell'; -import GenericCell from './cells/GenericCell'; const propTypes = { - batch: PropTypes.object, results: PropTypes.array, - columns: PropTypes.array, - headerCellClass: PropTypes.func.isRequired, - visibleWidth: PropTypes.number, - searchHash: PropTypes.string + columns: PropTypes.array }; export default class AgencyLandingTable extends React.PureComponent { - shouldComponentUpdate(nextProps) { - if (!Immutable.is(nextProps.batch, this.props.batch)) { - return true; - } - else if (nextProps.visibleWidth !== this.props.visibleWidth) { - // re-render if the window size changed - return true; - } - else if (nextProps.searchHash !== this.props.searchHash) { - return true; - } - return false; - } - - prepareTable() { - let totalWidth = 0; - - const HeaderCell = this.props.headerCellClass; - - const columns = this.props.columns.map((column) => { - // For this table, make each column's width a percentage of the visible width - const adjustedWidth = (this.props.visibleWidth * column.width); - totalWidth += adjustedWidth; - let cellName = null; - if (column.columnName === 'agency_name') { - cellName = (index) => ( - - ); - } - else { - cellName = (index) => ( - - ); - } - return { - width: adjustedWidth, - name: column.columnName, - columnId: `${column.columnName}`, - header: ( - - ), - cell: cellName - }; - }); - - return { - columns, - width: totalWidth - }; - } - render() { - const calculatedValues = this.prepareTable(); - let noResultsClass = ''; if (this.props.results.length === 0) { // remove duplicated bottom border noResultsClass = ' no-results'; } - const rowCount = this.props.results.length; - const rows = []; - for (let i = 0; i <= (rowCount - 1); i++) { - const row = (); - rows.push(row); - } + + const rows = this.props.results.map((agency, index) => ( + + )); return (
    -
    +
    + columns={this.props.columns} /> {rows} diff --git a/src/js/components/agencyLanding/table/HeaderRow.jsx b/src/js/components/agencyLanding/table/HeaderRow.jsx index fe6df68e1f..cfc5950d12 100644 --- a/src/js/components/agencyLanding/table/HeaderRow.jsx +++ b/src/js/components/agencyLanding/table/HeaderRow.jsx @@ -6,7 +6,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import HeaderCell from './HeaderCell'; +import AgencyLandingHeaderCellContainer from + 'containers/agencyLanding/table/AgencyLandingHeaderCellContainer'; const propTypes = { columns: PropTypes.array @@ -14,8 +15,12 @@ const propTypes = { export default class HeaderRow extends React.Component { render() { - const headers = this.props.columns.map((column) => ( - + const headers = this.props.columns.map((column, i) => ( + )); return ( diff --git a/src/js/components/agencyLanding/table/TableRow.jsx b/src/js/components/agencyLanding/table/TableRow.jsx index eab0bcf597..8aa6be9a0a 100644 --- a/src/js/components/agencyLanding/table/TableRow.jsx +++ b/src/js/components/agencyLanding/table/TableRow.jsx @@ -5,27 +5,41 @@ import React from 'react'; import PropTypes from 'prop-types'; -import TableCell from './TableCell'; +import AgencyLinkCell from './cells/AgencyLinkCell'; +import GenericCell from './cells/GenericCell'; const propTypes = { columns: PropTypes.array.isRequired, - dataHash: PropTypes.string, + agency: PropTypes.object, rowIndex: PropTypes.number.isRequired }; export default class TableRow extends React.PureComponent { - shouldComponentUpdate(nextProps) { - // force an update if the data hash has changed - return (nextProps.dataHash !== this.props.dataHash); - } - render() { - const cells = this.props.columns.map((column) => ( - - )); + const cells = this.props.columns.map((column) => { + if (column.columnName === 'agency_name') { + // show the agency link cell + return ( + + ); + } + return ( + + ); + }); return ( diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx index cafe9faf1e..5958857129 100644 --- a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -7,7 +7,7 @@ import React from 'react'; import PropTypes from 'prop-types'; const propTypes = { - name: PropTypes.array, + name: PropTypes.string, rowIndex: PropTypes.number, column: PropTypes.string, id: PropTypes.number diff --git a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx index d04bf5cb71..a9c2ddb1a1 100644 --- a/src/js/containers/agencyLanding/AgencyLandingContainer.jsx +++ b/src/js/containers/agencyLanding/AgencyLandingContainer.jsx @@ -5,25 +5,20 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { isCancel } from 'axios'; -import Immutable from 'immutable'; + +import { Search } from 'js-search'; +import { orderBy } from 'lodash'; import AgenciesTableFields from 'dataMapping/agencyLanding/agenciesTableFields'; -import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; -import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; import * as AgencyLandingHelper from 'helpers/agencyLandingHelper'; import * as MoneyFormatter from 'helpers/moneyFormatter'; import AgencyLandingContent from 'components/agencyLanding/AgencyLandingContent'; const propTypes = { - agencies: PropTypes.instanceOf(Immutable.OrderedSet), - agenciesOrder: PropTypes.object, - setAgencies: PropTypes.func, - meta: PropTypes.object, - autocompleteAgencies: PropTypes.array + agenciesOrder: PropTypes.object }; export class AgencyLandingContainer extends React.Component { @@ -34,7 +29,9 @@ export class AgencyLandingContainer extends React.Component { columns: [], inFlight: false, currentFY: '', - agencySearchString: '' + agencySearchString: '', + fullData: [], + results: [] }; this.agenciesRequest = null; @@ -48,7 +45,7 @@ export class AgencyLandingContainer extends React.Component { componentDidUpdate(prevProps) { if (this.props.agenciesOrder !== prevProps.agenciesOrder) { // table sort changed - this.fetchAgencies(); + this.performSearch(); } } @@ -59,8 +56,15 @@ export class AgencyLandingContainer extends React.Component { } setAgencySearchString(agencySearchString) { + let searchValue = ''; + if (agencySearchString.length > 2) { + searchValue = agencySearchString; + } + this.setState({ - agencySearchString + agencySearchString: searchValue + }, () => { + this.performSearch(); }); } @@ -141,49 +145,67 @@ export class AgencyLandingContainer extends React.Component { const percentage = (item.percentage_of_total_budget_authority * 100).toFixed(2); let percent = `${percentage}%`; - if (percentage === 0.00) { + if (percent === '0.00%') { percent = 'Less than 0.01%'; } - const agencyObject = { + const agency = { agency_id: item.agency_id, - agency_name: [`${item.agency_name} (${item.abbreviation})`], - budget_authority_amount: formattedCurrency, - percentage_of_total_budget_authority: percent + agency_name: `${item.agency_name} (${item.abbreviation})`, + budget_authority_amount: item.budget_authority_amount, + percentage_of_total_budget_authority: item.percentage_of_total_budget_authority, + display: { + agency_name: `${item.agency_name} (${item.abbreviation})`, + budget_authority_amount: formattedCurrency, + percentage_of_total_budget_authority: percent + } }; - - const agency = new Agency(agencyObject); agencies.push(agency); }); - this.props.setAgencies(agencies); + this.setState({ + fullData: agencies + }, () => { + this.performSearch(); + }); } - render() { - let results = this.props.agencies.toArray(); + performSearch() { + // perform a local search + const search = new Search('agency_id'); + search.addIndex('agency_name'); + search.addDocuments(this.state.fullData); - if (this.state.agencySearchString.length > 1) { - results = this.props.autocompleteAgencies; + // return the full data set if no search string is provided + let results = this.state.fullData; + if (this.state.agencySearchString !== '') { + results = search.search(this.state.agencySearchString); } - const resultsCount = results.length; + // now sort the results by the appropriate table column and direction + const orderedResults = orderBy(results, + [this.props.agenciesOrder.field], [this.props.agenciesOrder.direction]); + + this.setState({ + results: orderedResults + }); + } + + render() { + const resultsCount = this.state.results.length; let resultsText = `${resultsCount} results`; if (resultsCount === 1) { resultsText = `${resultsCount} result`; } - // Create an Ordered Set for the search hash - const autocompleteSet = new Immutable.OrderedSet(this.props.autocompleteAgencies); - return ( ); } @@ -193,10 +215,6 @@ AgencyLandingContainer.propTypes = propTypes; export default connect( (state) => ({ - agencies: state.agencyLanding.agencies, - agenciesOrder: state.agencyLanding.agenciesOrder, - meta: state.agencyLanding.agenciesMeta, - autocompleteAgencies: state.agencyLanding.autocompleteAgencies - }), - (dispatch) => bindActionCreators(agencyLandingActions, dispatch) + agenciesOrder: state.agencyLanding.agenciesOrder + }) )(AgencyLandingContainer); diff --git a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx b/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx deleted file mode 100644 index 3e0ef3ce3b..0000000000 --- a/src/js/containers/agencyLanding/AgencyLandingSearchBarContainer.jsx +++ /dev/null @@ -1,128 +0,0 @@ -/** - * AgencyLandingSearchBarContainer.jsx - * Created by Lizzie Salita 7/24/17 - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { bindActionCreators } from 'redux'; -import { connect } from 'react-redux'; -import { Search } from 'js-search'; -import Immutable from 'immutable'; -import reactStringReplace from 'react-string-replace'; - -import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; - -import AgencyLandingSearchBar from 'components/agencyLanding/AgencyLandingSearchBar'; - -const propTypes = { - setAgencySearchString: PropTypes.func, - setAutocompleteAgencies: PropTypes.func, - autocompleteAgencies: PropTypes.array, - agencies: PropTypes.instanceOf(Immutable.OrderedSet) -}; - -export class AgencyLandingSearchBarContainer extends React.Component { - constructor(props) { - super(props); - - this.state = { - inFlight: false, - autocompleteAgencies: [], - noResults: false, - agencySearchString: '' - }; - - this.agencySearchRequest = null; - this.handleTextInput = this.handleTextInput.bind(this); - this.timeout = null; - } - - componentWillUnmount() { - if (this.agencySearchRequest) { - this.agencySearchRequest.cancel(); - } - } - - handleTextInput(agencyInput) { - // Clear existing agencies - this.props.setAutocompleteAgencies([]); - - // Grab input, clear any exiting timeout - const input = agencyInput.target.value; - window.clearTimeout(this.timeout); - - // Perform search if user doesn't type again for 300ms - this.timeout = window.setTimeout(() => { - this.performSecondarySearch(input); - }, 300); - } - - performSecondarySearch(input) { - // Only search if input is 2 or more characters - if (input.length >= 2) { - this.props.setAgencySearchString(input); - this.setState({ - agencySearchString: input - }); - - // Convert agency Records to objects - const data = []; - this.props.agencies.forEach((agency) => { - const agencyObject = agency.toJS(); - data.push(agencyObject); - }); - - // Create a search index with the API response records - const search = new Search('agency_id'); - search.addIndex('agency_name'); - - // Add the API response as the data source to search within - search.addDocuments(data); - - // Use the JS search library to search within the records - const results = search.search(this.state.agencySearchString); - - const matchedAgencies = []; - results.forEach((item) => { - // highlight the matched substring - const updatedName = reactStringReplace(item.agency_name, this.state.agencySearchString, (match, i) => ( - {match} - )); - const updatedItem = Object.assign({}, item, { - agency_name: updatedName - }); - - matchedAgencies.push(updatedItem); - }); - - // Add search results to Redux - this.props.setAutocompleteAgencies( - matchedAgencies - ); - } - else { - this.props.setAgencySearchString(''); - this.setState({ - agencySearchString: '' - }); - } - } - - render() { - return ( - - ); - } -} - -AgencyLandingSearchBarContainer.propTypes = propTypes; - -export default connect( - (state) => ({ - agencies: state.agencyLanding.agencies, - autocompleteAgencies: state.agencyLanding.autocompleteAgencies - }), - (dispatch) => bindActionCreators(agencyLandingActions, dispatch) -)(AgencyLandingSearchBarContainer); diff --git a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx index cd4b01b5fb..36995d8246 100644 --- a/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx +++ b/src/js/containers/agencyLanding/table/AgencyLandingHeaderCellContainer.jsx @@ -20,7 +20,11 @@ const actions = { const propTypes = { setAgenciesOrder: PropTypes.func, - order: PropTypes.object + order: PropTypes.object, + displayName: PropTypes.string, + defaultDirection: PropTypes.string, + columnName: PropTypes.string, + isLast: PropTypes.bool }; class AgencyLandingHeaderCellContainer extends React.Component { @@ -40,7 +44,11 @@ class AgencyLandingHeaderCellContainer extends React.Component { render() { return ( ); } diff --git a/src/js/dataMapping/agencyLanding/agenciesTableFields.js b/src/js/dataMapping/agencyLanding/agenciesTableFields.js index b676d2cb12..4be753065e 100644 --- a/src/js/dataMapping/agencyLanding/agenciesTableFields.js +++ b/src/js/dataMapping/agencyLanding/agenciesTableFields.js @@ -11,8 +11,8 @@ const agenciesTableFields = { 'percentage_of_total_budget_authority' ], agency_name: 'Agency Name', - budget_authority_amount: 'Budget Authority', - percentage_of_total_budget_authority: 'Percent of Total U.S. Budget' + budget_authority_amount: 'Budgetary Resources', + percentage_of_total_budget_authority: 'Percent of Total' }; export default agenciesTableFields; diff --git a/src/js/redux/actions/agencyLanding/agencyLandingActions.js b/src/js/redux/actions/agencyLanding/agencyLandingActions.js index 732c6ce84c..403d9b8868 100644 --- a/src/js/redux/actions/agencyLanding/agencyLandingActions.js +++ b/src/js/redux/actions/agencyLanding/agencyLandingActions.js @@ -3,17 +3,7 @@ * Created by Lizzie Salita 7/10/17 */ -export const setAgencies = (state) => ({ - type: 'SET_AGENCIES', - agencies: state -}); - export const setAgenciesOrder = (state) => ({ type: 'SET_AGENCIES_ORDER', order: state }); - -export const setAutocompleteAgencies = (state) => ({ - type: 'SET_AUTOCOMPLETE_AGENCIES', - agencies: state -}); diff --git a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js index b3d88815ae..2d7f6ba0be 100644 --- a/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js +++ b/src/js/redux/reducers/agencyLanding/agencyLandingReducer.js @@ -3,47 +3,15 @@ * Created by Lizzie Salita 7/10/17 */ -import { uniqueId } from 'lodash'; -import { Record, OrderedSet } from 'immutable'; - -export const Agency = Record({ - agency_id: 0, - agency_name: '', - budget_authority_amount: '', - percentage_of_total_budget_authority: '' -}); - const initialState = { - agencies: new OrderedSet(), agenciesOrder: { field: 'percentage_of_total_budget_authority', direction: 'desc' - }, - agenciesMeta: { - batch: { - queryId: uniqueId(), - searchId: uniqueId() - } - }, - autocompleteAgencies: [] + } }; - const agencyLandingReducer = (state = initialState, action) => { switch (action.type) { - case 'SET_AGENCIES': { - const meta = Object.assign({}, state.agenciesMeta, { - batch: { - queryId: uniqueId(), - searchId: uniqueId() - } - }); - - return Object.assign({}, state, { - agencies: new OrderedSet(action.agencies), - agenciesMeta: meta - }); - } case 'SET_AGENCIES_ORDER': { const order = Object.assign({}, state.agenciesOrder, action.order); @@ -51,11 +19,6 @@ const agencyLandingReducer = (state = initialState, action) => { agenciesOrder: order }); } - case 'SET_AUTOCOMPLETE_AGENCIES': { - return Object.assign({}, state, { - autocompleteAgencies: action.agencies - }); - } default: return state; } diff --git a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx index b113cae9ba..f99a52caec 100644 --- a/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx +++ b/tests/containers/agencyLanding/AgencyLandingContainer-test.jsx @@ -6,8 +6,6 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import sinon from 'sinon'; -import Immutable from 'immutable'; -import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; import { AgencyLandingContainer } from 'containers/agencyLanding/AgencyLandingContainer'; @@ -16,7 +14,7 @@ import AgencyLandingContent from import { mockComponent, unmockComponent } from '../../testResources/mockComponent'; -import { mockData, mockMeta, mockAgenciesOrder } from './mockToptierAgencies'; +import { mockData, mockPopulated, mockAgenciesOrder } from './mockToptierAgencies'; jest.mock('helpers/agencyLandingHelper', () => require('./agencyLandingHelper')); jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; @@ -27,6 +25,7 @@ const setupMount = (props) => mount(); // spy on specific functions inside the component const fetchAgenciesSpy = sinon.spy(AgencyLandingContainer.prototype, 'fetchAgencies'); const parseAgenciesSpy = sinon.spy(AgencyLandingContainer.prototype, 'parseAgencies'); +const performSearchSpy = sinon.spy(AgencyLandingContainer.prototype, 'performSearch'); describe('AgencyLandingContainer', () => { beforeAll(() => { @@ -36,10 +35,7 @@ describe('AgencyLandingContainer', () => { it('should make an API request on mount', async () => { // mount the container const container = setupMount({ - agencies: new Immutable.OrderedSet([]), - agenciesOrder: mockAgenciesOrder, - meta: mockMeta, - autocompleteAgencies: [] + agenciesOrder: mockAgenciesOrder }); await container.instance().agenciesRequest.promise; @@ -50,20 +46,18 @@ describe('AgencyLandingContainer', () => { // reset the spy fetchAgenciesSpy.reset(); parseAgenciesSpy.reset(); + performSearchSpy.reset(); }); - it('should make an API request when the sort order changes', async () => { + it('should perform a local search when the sort order changes', async () => { // mount the container const container = setupMount({ - agencies: new Immutable.OrderedSet([]), - agenciesOrder: mockAgenciesOrder, - meta: mockMeta, - autocompleteAgencies: [] + agenciesOrder: mockAgenciesOrder }); await container.instance().agenciesRequest.promise; - expect(fetchAgenciesSpy.callCount).toEqual(1); + expect(performSearchSpy.callCount).toEqual(1); // change the sort order container.setProps({ @@ -75,86 +69,51 @@ describe('AgencyLandingContainer', () => { await container.instance().agenciesRequest.promise; - expect(fetchAgenciesSpy.callCount).toEqual(2); + expect(performSearchSpy.callCount).toEqual(2); }); describe('showColumns', () => { it('should build the table', async () => { // mount the container const container = setup({ - agencies: new Immutable.OrderedSet([]), - agenciesOrder: mockAgenciesOrder, - meta: mockMeta, - autocompleteAgencies: [] + agenciesOrder: mockAgenciesOrder }); container.instance().showColumns(); await container.instance().agenciesRequest.promise; // validate the state contains the correctly parsed values - const expectedState = { - columns: [ - { - columnName: "agency_name", - defaultDirection: "asc", - displayName: "Agency Name" - }, - { - columnName: "budget_authority_amount", - defaultDirection: "desc", - displayName: "Budget Authority" - }, - { - columnName: "percentage_of_total_budget_authority", - defaultDirection: "desc", - displayName: "Percent of Total U.S. Budget" - } - ], - inFlight: false, - currentFY: '', - agencySearchString: '' - }; - - expect(container.state()).toEqual(expectedState); + const expectedState = [ + { + columnName: "agency_name", + defaultDirection: "asc", + displayName: "Agency Name" + }, + { + columnName: "budget_authority_amount", + defaultDirection: "desc", + displayName: "Budgetary Resources" + }, + { + columnName: "percentage_of_total_budget_authority", + defaultDirection: "desc", + displayName: "Percent of Total" + } + ]; + + expect(container.state().columns).toEqual(expectedState); }); }); describe('parseAgencies', () => { - it('should parse the API response and overwrite the Redux agencies', () => { - const expected = Object.assign({},new Immutable.OrderedSet([ - new Agency({ - agency_id: 1, - agency_name: ['Agency 1 (ABC)'], - budget_authority_amount: "$1,234,567", - percentage_of_total_budget_authority: "1.21%" - }), - new Agency({ - agency_id: 2, - agency_name: ['Agency 2 (XYZ)'], - budget_authority_amount: "$2,345,678", - percentage_of_total_budget_authority: "2.32%" - }) - ])); - - delete expected._jsid; - - const reduxAction = jest.fn((args) => { - const model = Object.assign({}, new Immutable.OrderedSet(args)); - //delete model._jsid; - - expect(model).toEqual(expected); - }); - + it('should parse the API response and update the container state', () => { const container = setup({ - agencies: new Immutable.OrderedSet([]), - agenciesOrder: mockAgenciesOrder, - meta: mockMeta, - autocompleteAgencies: [], - setAgencies: reduxAction + agenciesOrder: mockAgenciesOrder }); - // mount the container + // mount the container container.instance().parseAgencies(mockData); + expect(container.state().fullData).toEqual(mockPopulated); }); }); diff --git a/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx b/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx deleted file mode 100644 index 122f0b249c..0000000000 --- a/tests/containers/agencyLanding/AgencyLandingSearchBarContainer-test.jsx +++ /dev/null @@ -1,223 +0,0 @@ -/** - * AgencyLandingContainer-test.jsx - * Created by Lizzie Salita 7/18/17 - */ - -import React from 'react'; -import { mount, shallow } from 'enzyme'; -import sinon from 'sinon'; -import Immutable from 'immutable'; -import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; - -import { AgencyLandingSearchBarContainer } from - 'containers/agencyLanding/AgencyLandingSearchBarContainer'; -import { AgencyLandingSearchBar } from - 'components/agencyLanding/AgencyLandingSearchBar'; -import * as agencyLandingActions from 'redux/actions/agencyLanding/agencyLandingActions'; -import { mockAgencies } from './mockToptierAgencies'; - -jest.mock('helpers/agencyLandingHelper', () => require('./agencyLandingHelper')); -jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; - -const setup = (props) => mount(); - -describe('AgencyLandingSearchBarContainer', () => { - describe('Handling text input', () => { - it('should handle text input after 300ms', () => { - // setup the search bar container and call the function to type a single letter - const searchBarContainer = setup({ - setAgencySearchString: jest.fn(), - setNoResults: jest.fn(), - setAutocompleteAgencies: agencyLandingActions.setAutocompleteAgencies, - autocompleteAgencies: [], - agencies: mockAgencies - }); - - const searchQuery = { - target: { - value: 'N' - } - }; - - const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), - 'handleTextInput'); - - // Call handleTextInput function - searchBarContainer.instance().handleTextInput(searchQuery); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(1000); - - // the mocked SearchHelper waits 1 tick to resolve the promise, so wait for the tick - jest.runAllTicks(); - - // everything should be updated now - expect(handleTextInputSpy.callCount).toEqual(1); - - // reset the spies - handleTextInputSpy.reset(); - }); - - it('should call the performSecondarySearch method after text input', () => { - // setup the search bar container and call the function to type a single letter - const searchBarContainer = setup({ - setAgencySearchString: jest.fn(), - setNoResults: jest.fn(), - setAutocompleteAgencies: agencyLandingActions.setAutocompleteAgencies, - autocompleteAgencies: [], - agencies: mockAgencies - }); - - const searchQuery = { - target: { - value: 'N' - } - }; - - const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), - 'handleTextInput'); - const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), - 'performSecondarySearch'); - - // Call handleTextInput function - searchBarContainer.instance().handleTextInput(searchQuery); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(1000); - - // everything should be updated now - expect(handleTextInputSpy.callCount).toEqual(1); - expect(performSecondarySearchSpy.callCount).toEqual(1); - - // reset the spies - handleTextInputSpy.reset(); - performSecondarySearchSpy.reset(); - }); - it('should not search when only one character has been input', () => { - // setup mock redux actions for handling search results - const mockReduxAction = jest.fn(); - - // setup the agency list container and call the function to type a single letter - const searchBarContainer = setup({ - setAgencySearchString: jest.fn(), - setNoResults: jest.fn(), - setAutocompleteAgencies: mockReduxAction, - autocompleteAgencies: [], - agencies: mockAgencies - }); - - const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), - 'performSecondarySearch'); - const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), - 'handleTextInput'); - - const searchQuery = { - target: { - value: 'N' - } - }; - - // Call handleTextInput function - searchBarContainer.instance().handleTextInput(searchQuery); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(1000); - - // everything should be updated now - expect(handleTextInputSpy.callCount).toEqual(1); - expect(performSecondarySearchSpy.callCount).toEqual(1); - // The redux action is called once in handleTextInput to reset - expect(mockReduxAction).toHaveBeenCalledTimes(1); - - // reset the mocks and spies - handleTextInputSpy.reset(); - performSecondarySearchSpy.reset(); - }); - - it('should perform the search when more than one character has been entered', () => { - // setup mock redux actions for handling search results - const mockReduxAction = jest.fn(); - - // setup the agency list container and call the function to type an input string - const searchBarContainer = setup({ - setAgencySearchString: jest.fn(), - setNoResults: jest.fn(), - setAutocompleteAgencies: mockReduxAction, - autocompleteAgencies: [], - agencies: mockAgencies - }); - - // set up spies - const handleTextInputSpy = sinon.spy(searchBarContainer.instance(), - 'handleTextInput'); - const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), - 'performSecondarySearch'); - - const searchQuery = { - target: { - value: 'Department of' - } - }; - - // Call handleTextInput function - searchBarContainer.instance().handleTextInput(searchQuery); - - // Run fake timer for input delay - jest.useFakeTimers().runTimersToTime(1000); - - // everything should be updated now - expect(handleTextInputSpy.callCount).toEqual(1); - expect(performSecondarySearchSpy.calledWith(handleTextInputSpy)); - - // Reset spies - handleTextInputSpy.reset(); - performSecondarySearchSpy.reset(); - }); - - it('should populate Agencies with matching results after performing the search', () => { - // Setup redux state - // Only Agencies 1 & 3 have agency names with the substring we are using - const reduxState = [ - new Agency({ - "agency_id": 1, - "agency_name": ["", Agen, "cy 1"], - "budget_authority_amount": "1234567", - "percentage_of_total_budget_authority": "0.01211" - }).toJS(), - new Agency({ - "agency_id": 3, - "agency_name": ["", Agen, "cy 3"], - "budget_authority_amount": "2345678", - "percentage_of_total_budget_authority": "0.02322" - }).toJS() - ]; - - // setup mock redux actions for handling search results - const mockReduxAction = jest.fn((args) => { - expect(args[0].agency_id).toEqual(1); - expect(args[1].agency_id).toEqual(3); - }); - - // setup the agency list container and call the function to type a single letter - const searchBarContainer = setup({ - setAgencySearchString: jest.fn(), - setNoResults: jest.fn(), - setAutocompleteAgencies: mockReduxAction, - autocompleteAgencies: reduxState, - agencies: mockAgencies - }); - - // Set up spies - const performSecondarySearchSpy = sinon.spy(searchBarContainer.instance(), - 'performSecondarySearch'); - - searchBarContainer.instance().performSecondarySearch('Agen'); - - expect(performSecondarySearchSpy.callCount).toEqual(1); - expect(mockReduxAction).toHaveBeenCalled(); - - // Reset spies - performSecondarySearchSpy.reset(); - }); - }); -}); diff --git a/tests/containers/agencyLanding/agencyLandingHelper.js b/tests/containers/agencyLanding/agencyLandingHelper.js index d2cd83dd54..3f5a648403 100644 --- a/tests/containers/agencyLanding/agencyLandingHelper.js +++ b/tests/containers/agencyLanding/agencyLandingHelper.js @@ -1,4 +1,4 @@ -import { mockData, mockSearchResults } from './mockToptierAgencies'; +import { mockData } from './mockToptierAgencies'; export const fetchAllAgencies = () => ( { @@ -12,16 +12,3 @@ export const fetchAllAgencies = () => ( cancel: jest.fn() } ); - -export const fetchSearchResults = () => ( - { - promise: new Promise((resolve) => { - process.nextTick(() => { - resolve({ - data: mockSearchResults - }); - }); - }), - cancel: jest.fn() - } -); \ No newline at end of file diff --git a/tests/containers/agencyLanding/mockToptierAgencies.js b/tests/containers/agencyLanding/mockToptierAgencies.js index b356608d7e..9d37612d11 100644 --- a/tests/containers/agencyLanding/mockToptierAgencies.js +++ b/tests/containers/agencyLanding/mockToptierAgencies.js @@ -1,77 +1,81 @@ -import { Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; -import Immutable from 'immutable'; - export const mockData = { results: [ { + current_total_budget_authority_amount: 123.0, + active_fq: "2", + active_fy: "2017", agency_id: 1, - agency_name: 'Agency 1', - budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.01211', - abbreviation: 'ABC' + agency_name: "Agency 1", + obligated_amount: 123.0, + percentage_of_total_budget_authority: 0.655, + outlay_amount: 123.0, + budget_authority_amount: 123.0, + abbreviation: "ABC" }, { + current_total_budget_authority_amount: 234.0, + active_fq: "2", + active_fy: "2017", agency_id: 2, - agency_name: 'Agency 2', - budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.02322', - abbreviation: 'XYZ' - } - ] -}; - -export const mockSearchResults = { - results: [ - { - agency_id: 1, - agency_name:'Agency 1 (ABC)' + agency_name: "Agency 2", + obligated_amount: 234.0, + percentage_of_total_budget_authority: 0.345, + outlay_amount: 234.0, + budget_authority_amount: 234.0, + abbreviation: "XYZ" }, { - agency_id: 2, - agency_name:'Agency 2 (XYZ)' + current_total_budget_authority_amount: 0.10, + active_fq: "2", + active_fy: "2017", + agency_id: 3, + agency_name: "Agency 3", + obligated_amount: 0.10, + percentage_of_total_budget_authority: 0.00003, + outlay_amount: 0.10, + budget_authority_amount: 0.10, + abbreviation: "FFF" } ] }; -export const mockMeta = { - batch: { - queryId: "01", - searchId: "02" - } -}; - export const mockAgenciesOrder = { sort: 'agency_name', direction: 'desc' }; -export const mockAgencies = [ - new Agency( - { - agency_id: 1, - agency_name: 'Agency 1', - budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.01211', - abbreviation: 'ABC' +export const mockPopulated = [ + { + agency_id: 1, + agency_name: "Agency 1 (ABC)", + percentage_of_total_budget_authority: 0.655, + budget_authority_amount: 123.0, + display: { + agency_name: "Agency 1 (ABC)", + budget_authority_amount: "$123", + percentage_of_total_budget_authority: "65.50%" } - ), - new Agency( - { - agency_id: 2, - agency_name: 'Test 2', - budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.02322', - abbreviation: 'XYZ' + }, + { + agency_id: 2, + agency_name: "Agency 2 (XYZ)", + percentage_of_total_budget_authority: 0.345, + budget_authority_amount: 234.0, + display: { + agency_name: "Agency 2 (XYZ)", + budget_authority_amount: "$234", + percentage_of_total_budget_authority: "34.50%" } - ), - new Agency( - { - agency_id: 3, - agency_name: 'Agency 3', - budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.02322', - abbreviation: 'DEF' + }, + { + agency_id: 3, + agency_name: "Agency 3 (FFF)", + percentage_of_total_budget_authority: 0.00003, + budget_authority_amount: 0.10, + display: { + agency_name: "Agency 3 (FFF)", + percentage_of_total_budget_authority: "Less than 0.01%", + budget_authority_amount: "$0" } - ) + } ]; - diff --git a/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js b/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js index 8130709fe2..0c094eb7f1 100644 --- a/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js +++ b/tests/redux/reducers/agencyLanding/agencyLandingReducer-test.js @@ -3,70 +3,9 @@ * Created by Lizzie Salita 7/26/17 */ -import agencyLandingReducer, { initialState, Agency } from 'redux/reducers/agencyLanding/agencyLandingReducer'; -import Immutable from 'immutable'; +import agencyLandingReducer, { initialState } from 'redux/reducers/agencyLanding/agencyLandingReducer'; describe('agencyLandingReducer', () => { - describe('SET_AGENCIES', () => { - it('should add Agency objects to the Redux store', () => { - let state = agencyLandingReducer(initialState, {}); - - const model = [ - new Agency({ - agency_id: 1, - agency_name: 'Test 1', - budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.012' - }), - new Agency ({ - agency_id: 2, - agency_name: 'Test 2', - budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.023' - }) - ]; - const action = { - type: 'SET_AGENCIES', - agencies: model - }; - - state = agencyLandingReducer(state, action); - - const expectedState = new Immutable.OrderedSet([ - new Agency({ - agency_id: 1, - agency_name: 'Test 1', - budget_authority_amount: '1234567', - percentage_of_total_budget_authority: '0.012' - }), - new Agency ({ - agency_id: 2, - agency_name: 'Test 2', - budget_authority_amount: '2345678', - percentage_of_total_budget_authority: '0.023' - }) - ]); - expect(state.agencies).toEqual(expectedState); - }); - }); - - describe('SET_AUTOCOMPLETE_AGENCIES', () => { - it('should add Autocomplete Agency Ids to the Redux store', () => { - let state = agencyLandingReducer(initialState, {}); - - const model = [1, 2]; - - const action = { - type: 'SET_AUTOCOMPLETE_AGENCIES', - agencies: model - }; - - state = agencyLandingReducer(state, action); - - expect(state.autocompleteAgencies).toEqual(model); - }); - }); - describe('SET_AGENCIES_ORDER', () => { it('should add Autocomplete Agency Ids to the Redux store', () => { let state = agencyLandingReducer(initialState, {}); From 5bd79778eb3468a14db7dd9b09733a20fb03e3ab Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 3 Aug 2017 17:02:54 -0400 Subject: [PATCH 94/97] Add in substring highlighting --- .../agencyLanding/table/AgencyLandingTable.jsx | 6 ++++-- src/js/components/agencyLanding/table/TableRow.jsx | 4 +++- .../agencyLanding/table/cells/AgencyLinkCell.jsx | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx index fc063708a1..d6a92f5168 100644 --- a/src/js/components/agencyLanding/table/AgencyLandingTable.jsx +++ b/src/js/components/agencyLanding/table/AgencyLandingTable.jsx @@ -11,7 +11,8 @@ import TableRow from './TableRow'; const propTypes = { results: PropTypes.array, - columns: PropTypes.array + columns: PropTypes.array, + agencySearchString: PropTypes.string }; export default class AgencyLandingTable extends React.PureComponent { @@ -28,7 +29,8 @@ export default class AgencyLandingTable extends React.PureComponent { agency={agency} key={agency.agency_id} rowIndex={index} - columns={this.props.columns} /> + columns={this.props.columns} + agencySearchString={this.props.agencySearchString} /> )); return ( diff --git a/src/js/components/agencyLanding/table/TableRow.jsx b/src/js/components/agencyLanding/table/TableRow.jsx index 8aa6be9a0a..e7981772e7 100644 --- a/src/js/components/agencyLanding/table/TableRow.jsx +++ b/src/js/components/agencyLanding/table/TableRow.jsx @@ -11,7 +11,8 @@ import GenericCell from './cells/GenericCell'; const propTypes = { columns: PropTypes.array.isRequired, agency: PropTypes.object, - rowIndex: PropTypes.number.isRequired + rowIndex: PropTypes.number.isRequired, + agencySearchString: PropTypes.string }; export default class TableRow extends React.PureComponent { @@ -26,6 +27,7 @@ export default class TableRow extends React.PureComponent { rowIndex={this.props.rowIndex} name={this.props.agency.agency_name} id={this.props.agency.agency_id} + agencySearchString={this.props.agencySearchString} column={column.columnName} /> ); diff --git a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx index 5958857129..66670a6020 100644 --- a/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx +++ b/src/js/components/agencyLanding/table/cells/AgencyLinkCell.jsx @@ -5,12 +5,14 @@ import React from 'react'; import PropTypes from 'prop-types'; +import reactStringReplace from 'react-string-replace'; const propTypes = { name: PropTypes.string, rowIndex: PropTypes.number, column: PropTypes.string, - id: PropTypes.number + id: PropTypes.number, + agencySearchString: PropTypes.string }; export default class AgencyLinkCell extends React.Component { @@ -22,11 +24,19 @@ export default class AgencyLinkCell extends React.Component { rowClass = 'row-odd'; } + let name = this.props.name; + // highlight the matched string if applicable + if (this.props.agencySearchString !== '') { + name = reactStringReplace(this.props.name, this.props.agencySearchString, (match, i) => ( + {match} + )); + } + return ( From cd82b5004025d9dc4bfa6e210a3c5afd32053a51 Mon Sep 17 00:00:00 2001 From: Kevin Li Date: Thu, 3 Aug 2017 17:11:55 -0400 Subject: [PATCH 95/97] Scrollable table on mobile --- src/_scss/pages/agencyLanding/table/table.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/_scss/pages/agencyLanding/table/table.scss b/src/_scss/pages/agencyLanding/table/table.scss index fee7cfb17f..e41b203f38 100644 --- a/src/_scss/pages/agencyLanding/table/table.scss +++ b/src/_scss/pages/agencyLanding/table/table.scss @@ -1,10 +1,18 @@ .agency-landing-results-table { display: block; + overflow: scroll; + &.no-results { border: none; } table { margin-top: rem(15); + width: rem(500); + + @include media($tablet-screen) { + width: auto; + } + thead { tr { border-bottom: solid 1px $color-gray-lighter; From 8461e2bd5616ef1a2c32b01541206854ced4668d Mon Sep 17 00:00:00 2001 From: Elizabeth Salita Date: Thu, 3 Aug 2017 17:46:02 -0400 Subject: [PATCH 96/97] Changed budget authority to budgetary resources --- src/js/components/agency/overview/AgencyOverview.jsx | 2 +- .../visualizations/obligated/ObligatedVisualization.jsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/components/agency/overview/AgencyOverview.jsx b/src/js/components/agency/overview/AgencyOverview.jsx index d6f16d9262..438ab86f69 100644 --- a/src/js/components/agency/overview/AgencyOverview.jsx +++ b/src/js/components/agency/overview/AgencyOverview.jsx @@ -201,7 +201,7 @@ export default class AgencyOverview extends React.PureComponent {

    - Agencies spend their available budget authority by making binding + Agencies spend their available budgetary resources by making binding financial commitments called obligations. An agency incurs an obligation, for example, when it places an order, signs a contract, awards a grant, purchases a service, or takes other actions that require it to make a payment. @@ -113,7 +113,7 @@ takes other actions that require it to make a payment. In fiscal year {this.props.activeFY}*, {this.props.agencyName} has obligated

    - {amountObligated} against its {authority} in Budget Authority + {amountObligated} against its {authority} in Budgetary Resources

    Date: Fri, 4 Aug 2017 10:48:04 -0400 Subject: [PATCH 97/97] Temporarily disable Agency Landing page from Navbar --- src/js/components/sharedComponents/header/ProfileButton.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js/components/sharedComponents/header/ProfileButton.jsx b/src/js/components/sharedComponents/header/ProfileButton.jsx index 56e8865853..3579d323a0 100644 --- a/src/js/components/sharedComponents/header/ProfileButton.jsx +++ b/src/js/components/sharedComponents/header/ProfileButton.jsx @@ -66,8 +66,10 @@ export default class ProfileButton extends React.Component {
    + + + + + +