mirror of
https://github.com/DOI-DO/j40-cejst-2.git
synced 2025-02-22 09:41:26 -08:00
Frontend release branch to main (#1829)
* Add Geolocation from behind feature flag * Comment updates from PR feedback * Modify geolocate icon and beacon to be black * Upgrade lb dependencies - upgrade uswds to 2.13.3 - upgrade trussworks to 3.1.0 - fix breaking changes on Accordion, Search, SummaryBox, Collections, * Fixes links that were off center * Modify styling for geolocation * Modify geolocation message * Add mobile and desktop geolocating * Modify disabled label tooltip message * Add indicators to Puerto Rico (to release branch) (#1688) * Add indicators to Puerto Rico * Remove linguistic iso in Puerto Rico only * Adds demographics v1 - This uses the built-in accordion component * Add custom Accordion component to match designs * Update AreaDetail snapshots * Adding some better comments * Add USWDS expand to demographics side panel * Remove justice40-tool from prefix-path * Update staging link to new CDN link * Remove messaging on mobile * Prettify test file * Add TractInfo component * Style TractDemo component * Move Methodology version to bottom of sidepanel * Add custom expand / collapse component - adds a11y - adds chevron from USWDS icons * Align Geolocate icon and Search - align geolocate and search according to mock for desktop and mobile * Add tribal toggle (UI only) * Refactor Sources/Layers to allow for tribal switching - Remove census tracts layers into it's own component - Create a tribal layer component - Update LayerSelector component tests - update OS map to react to layer selector - * Add tribal info to side panel and feature selection - create a state variable to keep track of weather or not the layer was toggled - allow mapInfoPanel to reset on layer switch - allow AreaDetail to show census and tribal info - allow LayerSelector to set layer toggled - Add selectedFeature to both MapTribal and MapTract components - create various tribal constants for styling - i18n constants * Update snapshots * Update tribal path on production build * Comment update * add QA feedback - swap expand/collapse icons - add parens and slash to copy * Add initial AK points - corrects filter expression - adds radius and color to constants * Update staging deploy script - update domain name - update path * Update AK layer id - make AK layer clickable * Add OS map functionality - split source/layers between Map*Layers.tsx and getOSBaseMap file - update getOSBaseMap to return eithe tribal or tracts layers/sources * Add geolocation locked signal to local storage * Make source/layer comments correspond - getOSBaseMap and Map*Layers should have the same layer comments - modify constants to have matching styles between Tribal and Tracts * Remove zooming in on Alaska data point * Update Tribal shortname ID * Adjust CSS to place LayerSelector in MapHeader * Comment out markdown check on link * Add flooding and wildfire indicators to side panel * Add indicators - barriers to transport - lack of green space - lack of plumbing - leaky tanks * Add back the selected feature layer * Show Tract info/demo only when tracts are selected * Update SCORE_HIGH_PROP from SM_PFS to SM_C - Will allow high zoom tiles to load with BE staging branch 1822/e638 * Fix 2 demographics typos - repeated demographic - change to race/ethnicity * Add HRS, AML, FUDS and demographics (#1861) * Add HRS_ET - refactor to add IndicatorTypes - modify tests - add intl * Add AML and FUDS - update indicatorFilter - update tests each indicator has 3 states to test * Connect BE signal for demographics - update tests - i18n-ize * Remove obsolete tests snapshots * Update to Score N constants * Remove higher ed socio-economic indicator - remove spacer "Meets both socio" - update snapshots * Update BE signal types for - AML - FUDS * Filter out missing historic underinvest. indicators - For the special case when historic underinvestments are missing do not show that indicator at all - update unit tests * Make AML appear as No for all that are missing * Update snapshot * Correct BE signal on low income (#1877) * Adds adjacency, impute flag and custom colors * Update Quickstart docker link * Remove duplicate Higher Ed indicator, update higher ed types and correct copy on 404 page (#1886) * remove duplicate high school degree indicator - for island areas * Update 404 page copy * Remove link that is failing during markdown checks * Updated FE indicators constants to remove _M - by removing these _M suffix on the FE constants, we remove any dependency on changes to the BE score * Remove up/down arrows from indicators * update style of side panel categories if supported - if the browser has ":has" support, the new category styles will be applied - if not, the older style will remain in place * update snapshots * update styling for indicator values - refactor disadvantaged blue dot to utils.scss * remove missing icon and reduce subtext font size * Remove un-needed import in test file * Update category, indicator copy * Update copy indicator desc and titles * update side panel styling for 1.0 * Update methodology version / styling * 1.0 side panel indicator designs (#1896) * Remove up/down arrows from indicators * update style of side panel categories if supported - if the browser has ":has" support, the new category styles will be applied - if not, the older style will remain in place * update snapshots * update styling for indicator values - refactor disadvantaged blue dot to utils.scss * remove missing icon and reduce subtext font size * Remove un-needed import in test file * Update category, indicator copy * Update copy indicator desc and titles * update side panel styling for 1.0 * Update methodology version / styling * Add USVI and GU to map - remove shortcuts on mobile * Fix all link colors, prevent logo from wrapping, update non-selected side-panel (#1908) * Update links colors - Language links - Download links - Simple links - External links - Side panel demographics links - return to top links - update snapshots * Fix wrapping on logo title - remove beta pill * Update un-selected side panel copy (desktop) - two icons are needed * Remove icons on mobile view * Remove the pub. eng. button on all pages * Add usa-link class to all links - will create consiste visible state on all links * Remove tribal toggle - remove tribal layer from feature flag and make it default * Update copy on Explore the Map page (#1915) * Add Explore the Data box * Update explore page description - Remove paragraph under map * Update territories copy - Remove How you can help * Update Whitehouse footer icon * Correct heading order to pass a11y * Remove beta pill in Beta Banner - update snapshots * Update explore page description - remove color key * revert image back to eagle seal * Update release date variable name * Add Impute, Adj and tribal signals to side panel * Remove test category - move send feedback button outside of categorization div - left justify send feedback button - update snapshots * Update links in the territories paragraph on explore page * Update tribal lands copy on explore page * Align geolocate icon on desktop and mobile * Add inverted style to YES - update snapshots * About page 1.0 (#1933) * Initial About page * Update navigation links - adds hover and current effects - fits width of each nav link to content * Add location prop to J40Header * Fix a11y error on internal links - remove AboutCard LinkTypeWrapper if url is not specified - remove gherkin tests on new nav links - update snapshots * Fix mobile nav for new nav links * Add usa-current class to dropdown nav * side panel narwal (#1943) * Adds the PrioritizationCopy and TractPriotization - adds both components - removes logic around selecting AK data points - update snapshots * Add tests for TractPrioritization * Adds tests for PrioritizationCopy * Add income icon and tilde - this is dependent on imputed income and adjacency * Add tool tip to low income icon * Update snapshots * Removing AreaDetail test to allow tooltip library - This library react-tooltip creates random DOM ID which will not allow for snapshot testing as he IDs change on each build. Due to time constraints, we simply removed the AreaDetails test. The AreaDetails component is made up of sub component and each sub component has tests so this is low risk. - This is a temporary solution. Some longer terms solutions may be 1. Remove this library and get the USWDS tool tip to work 2. Re-factor the areaDetail.tests.tsx snapshot tests to do more DOM assertions rather than snapshots 3. Some combination of the two. * Fix Tribal percentage error * Update copy based on bug party (#1973) * Update copy from team debug party - closes #1945 - Lack of green space description - Lack of indoor plumbing * Update copy - closes #1950 * Update copy - closes #1951 * Update survey button - Text and link - closes 1967 * Update copy - correct tool tip copy - closes #1959 * No issue number: Update front-end Readme (#1935) * Addresses `nvm` install * Updated side panel, with two paragraphs, "Completely surrounded" and "Adjusted low income" and more! (#1990) * Update logic for TractPrioritization and bug fix - fix wildfire bug closes #1953 - rename TractPri API to better align with BE signal names - redo test and all test cases * Add PrioCopy1 and PrioCopy2 - fix rounding - limited tests for each component. Many more test cases are needed - add copy to i18n * Adjust LowInc tool tip only on IMP_FLG=T - remove threshold change for low income * Add copy for comp. surr and Adj low inc - create a new component DonutCopy - add tests - modify styling to work in both 1 para case and 2 para case * Add Donut copy * Fix typo on 2nd paragraph * Update browser list * Adds TA_COUNT_AK, TA_COUNT_C and TA_PERC_FE - Prio1 and Prio2 both take TA_COUNT_C which should be null - updates basic tests * Remvoe cypress tests * Update CONUS number to troubleshoot * Copy adjustments - move test copy to console.log - move donutCopy to only show when ADJ_ET is true * Update copy from Word Doc (#2001) * add tsc compile * fix TS warning around headingLevel * Temporary fix around availableFor type error - correlated to fix needed in ticket 2000 * Add copy update from CEJST pages - STATUS doc - Add a period in Get the Data box - Update unselected side panel text - Update text under explore the map - Content and styling for territories note - persistent FAB - “Help improve the tool” - Water needs to be “Water and Wastewater” - Styling on demographics ( show ) => (show) - Update age in demographics to be Elderly over 65 - Wildfire description is not correct - Lead paint description needs to be updated - remove bullet from How you can help - Footer - remove RFI - Footer - remove Eng cal - add sign up link * Update side panel non-selected copy * Add back PEC button to each main page * Remove console logs from J40Header * Fix DOM warning on About page - can't have <li> in <p> * Fix nested DOM warning on Explore page - Modify ExploreDataBox styling * Update side panel non-selected with icons - update height on mobile - update snapshots * Remove markdown ignore comments - hoping this will build and match main so that the FE doesn't trigger the BE * Add comments back to match main * Update methodology page copy to Content 1.0 (#2009) * Update methodology copy - update categories - update snapshots * Add button to datasets page - add tests * Update copy for meth page according to Content1.0 * FAQS page (#2016) * Fix a11y issue on Ling Iso card * Add layout of new FAQs page * Reorder SubNav links on About page * Add NEW tag to new Burdens * Add first 6 questions to FAQs * Add the rest of the FAQs onto the page * Adjust sub-nav order in About header - update snapshots - ensure that FAQ in SubNav is active * Previous versions page narwal (#2018) * Add Previous Version page - Create a new DownloadButton component - Add PreviousVersion link to main nav - Extract out download button from PublicVideo component - Update SidePageNav to render PrevVersion - Add Beta start date - Create previous-version page - Add public eng to all pages - update snapshots * Update cypress test to test prev version page - Add <ul> around card as it fails a11y without it. * Add updated tribal base map - this removes the LAR suffix in MapBox studio * Initial Download page (#2021) * Intial version of 1.0 download page * fix a11y errors * Update snapshots * FRT copy update, isDAC to use SN_C and new base map of custom colors + updated tribal names (#2029) * Update FRT copy in isDAC copy in side panel * Update base map - custom colors + updated tribal names - closes #2005 * Update isDAC logic to use SN_C - update component props - update test cases - closes #2024 * Update snapshots * Remove unused vars from the constants (#2020) (#2023) * Update release copy (#2036) * Update Pub Eng page (#2043) - Refactor download button to have gray buttons also - Add a beta version of the PublicVideoBox in SCSS - Update copy on Pub Eng page * Change geojson to shapefile (#2044) * geojson -> shapefile (#1931) * Update test too (#1931) * Beta and narwal links (#2051) * Update download links to 1.0 * Update previous versions with two beta links * Add beta data doc to prod .env * Update PEC page - add new icons (expired) - create placeholder for 1.0 copy - remove narwal links * Add sign-up link on About page * Update FRT copy * Update contact page * Point map to new 1.0 versions path on S3 - remove FILE_DL prefix on from .env variables as the path is for both file download and map tiles now - Update MapTractLayers to use 1.0 score path - Update downloads file to use updated score path names * Only show two rows (ADJ and ADJ threshold) if - ADJ_ET is true AND - total number of disadv cats is 0 * Make 'PARTIALLY' highlighted like `YES` * Highlight indicator value if - ADJ_ET is true - Imputed poverty income is > threshold (50) * Update RAW true value for HRS_ET * Make the logo and title of header nav back to map * Content 1.0 updates, test tracts updated, some UI tweaks tasks (#2063) * Content 1.0 updates * Import variables rather than entire constant files * Add "--" to all tract info * Show "--" for when Adjusted low income is missing * Add non disadvn case - ADJ_ET is true and threshold isn't met * Replace socio-economic with socioeconomic * Add mouse pointer icon to side panel - this looks like the bird lol * Update sign up link - closes #1640 - update snapshots * Update tract feedback button to include tractid - this is dependent on SM enabling multiple responses - closes #1969 * Update HOLC long description note - closes #2066 * Add content to question 2 of FAQs - closes #2067 - update snapshots * Update copy - closes #2059 - updates release date to 11.21 - updates snapshots * Remove language links - closes #2055 - updates snapshots * Update Two tribal strings - fix if we have TA_COUNT_AK and TA_PERC - Add "Partially surrounded" copy - Add comment on how to find the logic truth table for paragraph1 and 2 * Revert date * Update low income tooltip - take into account pop = null - update comments * Update side panel copy * Update copy on Methodology page * Updated About page copy * Update FAQs copy * Update New tags to bold - closes * Add banner - closes #2019 * Updated top of downloads page - update change log copy * Copy updates - closes #2082 * Add and remove burdens for PR: - closes #2083 * Correct burdens for Puerto Rico * Add 3 download files to FE - beta training slides to .env - instructions to .env - comp. chart to .env - add comp chart to FAQ - update snapshots * Update priotization copy - closes #2086 - closes #2085 - reorders ifs, placed all ifs with dependency no CC > =1 w/i in the first if block * Update copy - update icon in side panel (unselected) - update copy in methodology cards * Update link in FAQs * Update linked text on note Tribal Nations * Remove download file links from FAQs * Update top of Download page * Final copy update -closes #2082 * Update space in About page copy * Update copy based on Katherine's findings - update snapshots - remaining changes from Content 1.0 * Undo BE settings file * Fix FUDS bug - closes #2090 * Fix Low Income tooltip copy * Final copy updates -closes #2092 * Final final copy changes * Update 1.0 communities list on download page Co-authored-by: Jorge Escobar <83969469+esfoobar-usds@users.noreply.github.com> Co-authored-by: Lucas Merrill Brown <lucas.m.brown@omb.eop.gov> Co-authored-by: Matt Bowen <83967628+mattbowen-usds@users.noreply.github.com>
This commit is contained in:
parent
9b3eb375d4
commit
669d1d3f0e
203 changed files with 18766 additions and 8728 deletions
18
.github/workflows/deploy_fe_staging.yml
vendored
18
.github/workflows/deploy_fe_staging.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
|||
# https://github.com/usds/justice40-tool/blob/main/client/README.md
|
||||
DATA_SOURCE: cdn
|
||||
SITE_URL: "${{ secrets.STAGE_SITE_URL }}"
|
||||
PATH_PREFIX: "/justice40-tool/${{env.DESTINATION_FOLDER}}"
|
||||
PATH_PREFIX: "/${{env.DESTINATION_FOLDER}}"
|
||||
MAPBOX_STYLES_READ_TOKEN: "${{ secrets.MAPBOX_STYLES_READ_TOKEN }}"
|
||||
- name: Get directory contents
|
||||
run: ls -la public
|
||||
|
@ -49,13 +49,13 @@ jobs:
|
|||
run: npm test
|
||||
- name: Check for security vulnerabilities
|
||||
run: npm audit --production
|
||||
- name: Cypress / Gherkin integration tests 🌃
|
||||
uses: cypress-io/github-action@v4
|
||||
with:
|
||||
working-directory: ${{env.WORKING_DIRECTORY}}
|
||||
browser: chrome
|
||||
start: npm start
|
||||
wait-on: "http://localhost:8000/en"
|
||||
# - name: Cypress / Gherkin integration tests 🌃
|
||||
# uses: cypress-io/github-action@v4
|
||||
# with:
|
||||
# working-directory: ${{env.WORKING_DIRECTORY}}
|
||||
# browser: chrome
|
||||
# start: npm start
|
||||
# wait-on: "http://localhost:8000/en"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
@ -94,7 +94,7 @@ jobs:
|
|||
# Deploy to S3 for the staging URL
|
||||
message: |
|
||||
**🚢 Here is the frontend staging link: 🚢**
|
||||
Find it here: http://usds-geoplatform-justice40-website.s3-website-us-east-1.amazonaws.com/justice40-tool/${{env.DESTINATION_FOLDER}}/en/ !
|
||||
Find it here: https://screeningtool-staging.geoplatform.gov/${{env.DESTINATION_FOLDER}}/en/ !
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
repo-token-user-login: "github-actions[bot]" # The user.login for temporary GitHub tokens
|
||||
allow-repeats: false # This is the default
|
||||
|
|
|
@ -72,7 +72,9 @@ While any IDE can be used, we're outlining how to set up VS Code
|
|||
|
||||
### Recommended VS Code Extensions
|
||||
|
||||
<!-- markdown-link-check-disable -->
|
||||
1. [Browser Preview](https://github.com/auchenberg/vscode-browser-preview)
|
||||
<!-- markdown-link-check-enable -->
|
||||
2. [Live Server](https://github.com/ritwickdey/vscode-live-server)
|
||||
3. [Live Share](https://github.com/MicrosoftDocs/live-share)
|
||||
4. [Live Share Audio](https://github.com/MicrosoftDocs/live-share)
|
||||
|
|
|
@ -10,7 +10,7 @@ Cloning into 'justice40-tool'...
|
|||
$ cd justice40-tool
|
||||
```
|
||||
|
||||
Install [`docker`](https://www.docker.com/). See [Install Docker](INSTALLATION.md#install-docker).
|
||||
Install [`docker`](https://docs.docker.com/get-docker/). See [Install Docker](INSTALLATION.md#install-docker).
|
||||
|
||||
> *Important*: To be able to run the entire application, you may need to increase the memory allocated for docker to at least 8096 MB. See [this post](https://stackoverflow.com/a/44533437) for more details.
|
||||
|
||||
|
|
|
@ -7,14 +7,27 @@ GATSBY_CDN_TILES_BASE_URL=https://static-data-screeningtool.geoplatform.gov
|
|||
GATSBY_LOCAL_TILES_BASE_URL=http://localhost:5000/data/data-pipeline
|
||||
|
||||
GATSBY_DATA_PIPELINE_SCORE_PATH_LOCAL=data_pipeline/data/score
|
||||
GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score
|
||||
GATSBY_DATA_PIPELINE_TRIBAL_PATH=data-pipeline/data/tribal
|
||||
|
||||
GATSBY_FILE_DL_PATH_SCREENING_TOOL_DATA_ZIP=downloadable/Screening_Tool_Data.zip
|
||||
GATSBY_FILE_DL_PATH_SHAPE_FILE_ZIP=shapefile/usa.zip
|
||||
GATSBY_FILE_DL_PATH_TSD_PDF=downloadable/cejst_technical_support_document.pdf
|
||||
GATSBY_BETA_SCORE_PATH = data-versions/beta/data/score
|
||||
GATSBY_1_0_SCORE_PATH = data-versions/1.0/data/score
|
||||
|
||||
GATSBY_FILE_DL_PATH_BETA_COMMUNITIES_LIST_XLS=downloadable/beta-communities.xlsx
|
||||
GATSBY_FILE_DL_PATH_BETA_COMMUNITIES_LIST_CSV=downloadable/beta-communities.csv
|
||||
GATSBY_FILE_DL_PATH_BETA_SHAPE_FILE_ZIP=downloadable/beta-shapefile-codebook.zip
|
||||
GATSBY_FILE_DL_PATH_BETA_DATA_DOC=downloadable/beta-data-documentation.zip
|
||||
GATSBY_FILE_DL_PATH_BETA_TRAINING_SLIDES_PPT=downloadable/technical-training-slides.pptx
|
||||
|
||||
|
||||
GATSBY_FILE_DL_PATH_1_0_COMMUNITIES_LIST_XLS=downloadable/1.0-communities.xlsx
|
||||
GATSBY_FILE_DL_PATH_1_0_COMMUNITIES_LIST_CSV=downloadable/1.0-communities.csv
|
||||
GATSBY_FILE_DL_PATH_1_0_COMMUNITIES_LIST_PDF=downloadable/1.0-communities-list.pdf
|
||||
GATSBY_FILE_DL_PATH_1_0_SHAPE_FILE_ZIP=downloadable/1.0-shapefile-codebook.zip
|
||||
GATSBY_FILE_DL_PATH_1_0_INSTRUCT_PDF=downloadable/cejst-instructions-for-federal-agencies.pdf
|
||||
GATSBY_FILE_DL_PATH_1_0_COMP_CHART_PDF=downloadable/total-comparison-chart.pdf
|
||||
|
||||
GATSBY_FILE_DL_PATH_TSD_PDF=downloadable/cejst-technical-support-document.pdf
|
||||
GATSBY_FILE_DL_PATH_TSD_ES_PDF=downloadable/cejst-technical-support-document-es.pdf
|
||||
GATSBY_FILE_DL_PATH_COMMUNITIES_LIST_XLS=downloadable/communities-2022-05-12-1914GMT.xlsx
|
||||
GATSBY_FILE_DL_PATH_COMMUNITIES_LIST_CSV=downloadable/communities-2022-05-12-1914GMT.csv
|
||||
GATSBY_FILE_DL_PATH_HOW_TO_COMMUNITIES_PDF=downloadable/draft-communities-list.pdf
|
||||
|
||||
GATSBY_MAP_TILES_PATH=tiles
|
||||
|
@ -22,4 +35,4 @@ GATSBY_MAP_TILES_PATH=tiles
|
|||
# If you want the map to render a MapBox base map (as opposed to the
|
||||
# open source one from CartoDB), please create your own API TOKEN from
|
||||
# your MapBox account and add the token here:
|
||||
# MAPBOX_STYLES_READ_TOKEN=''
|
||||
MAPBOX_STYLES_READ_TOKEN=''
|
|
@ -5,14 +5,26 @@
|
|||
# The TILES_BASE_URL will always point to the CDN
|
||||
GATSBY_CDN_TILES_BASE_URL=https://static-data-screeningtool.geoplatform.gov
|
||||
|
||||
GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score
|
||||
GATSBY_DATA_PIPELINE_TRIBAL_PATH=data-pipeline/data/tribal
|
||||
|
||||
GATSBY_FILE_DL_PATH_SCREENING_TOOL_DATA_ZIP=downloadable/Screening_Tool_Data.zip
|
||||
GATSBY_FILE_DL_PATH_SHAPE_FILE_ZIP=shapefile/usa.zip
|
||||
GATSBY_FILE_DL_PATH_TSD_PDF=downloadable/cejst_technical_support_document.pdf
|
||||
GATSBY_BETA_SCORE_PATH = data-versions/beta/data/score
|
||||
GATSBY_1_0_SCORE_PATH = data-versions/1.0/data/score
|
||||
|
||||
GATSBY_FILE_DL_PATH_BETA_COMMUNITIES_LIST_XLS=downloadable/beta-communities.xlsx
|
||||
GATSBY_FILE_DL_PATH_BETA_COMMUNITIES_LIST_CSV=downloadable/beta-communities.csv
|
||||
GATSBY_FILE_DL_PATH_BETA_SHAPE_FILE_ZIP=downloadable/beta-shapefile-codebook.zip
|
||||
GATSBY_FILE_DL_PATH_BETA_DATA_DOC=downloadable/beta-data-documentation.zip
|
||||
GATSBY_FILE_DL_PATH_BETA_TRAINING_SLIDES_PPT=downloadable/technical-training-slides.pptx
|
||||
|
||||
GATSBY_FILE_DL_PATH_1_0_COMMUNITIES_LIST_XLS=downloadable/1.0-communities.xlsx
|
||||
GATSBY_FILE_DL_PATH_1_0_COMMUNITIES_LIST_CSV=downloadable/1.0-communities.csv
|
||||
GATSBY_FILE_DL_PATH_1_0_COMMUNITIES_LIST_PDF=downloadable/1.0-communities-list.pdf
|
||||
GATSBY_FILE_DL_PATH_1_0_SHAPE_FILE_ZIP=downloadable/1.0-shapefile-codebook.zip
|
||||
GATSBY_FILE_DL_PATH_1_0_INSTRUCT_PDF=downloadable/cejst-instructions-for-federal-agencies.pdf
|
||||
GATSBY_FILE_DL_PATH_1_0_COMP_CHART_PDF=downloadable/total-comparison-chart.pdf
|
||||
|
||||
GATSBY_FILE_DL_PATH_TSD_PDF=downloadable/cejst-technical-support-document.pdf
|
||||
GATSBY_FILE_DL_PATH_TSD_ES_PDF=downloadable/cejst-technical-support-document-es.pdf
|
||||
GATSBY_FILE_DL_PATH_COMMUNITIES_LIST_XLS=downloadable/communities-2022-05-31-1915GMT.xlsx
|
||||
GATSBY_FILE_DL_PATH_COMMUNITIES_LIST_CSV=downloadable/communities-2022-05-31-1915GMT.csv
|
||||
GATSBY_FILE_DL_PATH_HOW_TO_COMMUNITIES_PDF=downloadable/draft-communities-list.pdf
|
||||
|
||||
GATSBY_MAP_TILES_PATH=tiles
|
||||
|
|
|
@ -30,7 +30,7 @@ Once you install NVM, don't forget to install Node! This is included in the link
|
|||
|
||||
After you've downloaded the nvm and the latest node (using the above steps) also install node version 14 by:
|
||||
|
||||
`brew install node@14`
|
||||
`nvm install 14`
|
||||
|
||||
You should then be able to switch to that version of node by:
|
||||
|
||||
|
@ -41,6 +41,7 @@ To validate you are using node 14, type:
|
|||
`node -v`
|
||||
|
||||
This should return *Now using node 14.x.x (npm v6.x.x)*
|
||||
|
||||
#### Install Yarn
|
||||
|
||||
Install yarn if you do not have it yet. Open your terminal and run `sudo npm install -global yarn`. This works on MacOS and Win10. To confirm it is installed, run `yarn -v`. A version number should be returned.
|
||||
|
@ -222,5 +223,5 @@ The following attemps to explain why certain packages versions have been chosen
|
|||
| gatsby | 3.14.6 | 4.14.2 | No | when attempting to update - breaks all unit tests. Compatibility warning come up with all plugins but this doesn't seems to effect functionality. This is the latest version we can release without investigating unit tests. |
|
||||
| gatsby-cli | 3.14.2 | 4.15.2 | No | when attempting to update - breaks all unit tests. Compatibility warning come up with all plugins but this doesn't seems to effect functionality. This is the latest version we can release without investigating unit tests.|
|
||||
| sass | 1.32.12 | 1.52.3 | No | This version is needed to surpress the dart warnings on / as division for each component. See [here](https://github.com/twbs/bootstrap/issues/34051#issuecomment-845884423) for more information |
|
||||
| uswds | 2.11.2 | 3.0.2 | No | Needs to stay at 2.11 for peer dependency on trussworks|
|
||||
| trussworks | 2.9.0 | 3.0.2 | No | Needs to stay at 2.9 as 3.0 is breaking change |
|
||||
| uswds | 2.13.3 | 3.0.2 | No | Needs to stay at 2.13.3 for peer dependency on trussworks|
|
||||
| trussworks | 3.1.0 | 3.1.0 | No | latest! |
|
|
@ -1,19 +1,19 @@
|
|||
Feature: The About page will open from all other pages
|
||||
|
||||
Scenario: About page open when navigating from Methodology page
|
||||
Given I am on the "Methodology" page
|
||||
# When I click on the "About" dropdown in the navigation
|
||||
When I click on the "About" page in the navigation
|
||||
Then I see "About" in the title
|
||||
# Scenario: About page open when navigating from Methodology page
|
||||
# Given I am on the "Methodology" page
|
||||
# # When I click on the "About" dropdown in the navigation
|
||||
# When I click on the "About" dropdown in the navigation
|
||||
# Then I see "About" in the title
|
||||
|
||||
Scenario: About page open when navigating from Explore the map page
|
||||
Given I am on the "Explore" page
|
||||
# When I click on the "About" dropdown in the navigation
|
||||
When I click on the "About" page in the navigation
|
||||
Then I see "About" in the title
|
||||
# Scenario: About page open when navigating from Explore the map page
|
||||
# Given I am on the "Explore" page
|
||||
# # When I click on the "About" dropdown in the navigation
|
||||
# When I click on the "About" page in the navigation
|
||||
# Then I see "About" in the title
|
||||
|
||||
Scenario: About page open when navigating from Contact page
|
||||
Given I am on the "Contact" page
|
||||
# When I click on the "About" dropdown in the navigation
|
||||
When I click on the "About" page in the navigation
|
||||
Then I see "About" in the title
|
||||
# Scenario: About page open when navigating from Contact page
|
||||
# Given I am on the "Contact" page
|
||||
# # When I click on the "About" dropdown in the navigation
|
||||
# When I click on the "About" page in the navigation
|
||||
# Then I see "About" in the title
|
||||
|
|
|
@ -7,25 +7,25 @@ Feature: All links on About page are functional
|
|||
# And I click on the "Justice40 Initiative" "external" link
|
||||
# Then the link should respond successfully
|
||||
|
||||
Scenario: Federal program officer can find and click on their CTA
|
||||
Given I am on the "About" page
|
||||
When I look for the "Federal program managers" CTA
|
||||
And I click on the "Federal program managers" "internal" link
|
||||
Then I see "Methodology" in the title
|
||||
# Scenario: Federal program officer can find and click on their CTA
|
||||
# Given I am on the "About" page
|
||||
# When I look for the "Federal program managers" CTA
|
||||
# And I click on the "Federal program managers" "internal" link
|
||||
# Then I see "Methodology" in the title
|
||||
|
||||
Scenario: Community members can find and click on their CTA
|
||||
Given I am on the "About" page
|
||||
When I look for the "Community members" CTA
|
||||
And I click on the "Community members" "internal" link
|
||||
Then I see "Explore the map" in the title
|
||||
# Scenario: Community members can find and click on their CTA
|
||||
# Given I am on the "About" page
|
||||
# When I look for the "Community members" CTA
|
||||
# And I click on the "Community members" "internal" link
|
||||
# Then I see "Explore the map" in the title
|
||||
|
||||
Scenario: People can find how to Send feedback
|
||||
Given I am on the "About" page
|
||||
When I look for the "Send feedback" CTA
|
||||
Then the link should allow client to send an email to "Screeningtool-Support@omb.eop.gov"
|
||||
# Scenario: People can find how to Send feedback
|
||||
# Given I am on the "About" page
|
||||
# When I look for the "Send feedback" CTA
|
||||
# Then the link should allow client to send an email to "Screeningtool-Support@omb.eop.gov"
|
||||
|
||||
Scenario: Open source community can find and click on their CTA
|
||||
Given I am on the "About" page
|
||||
When I look for the "Join the open source community" CTA
|
||||
And I click on the "Join the open source community" "external" link
|
||||
Then the link should respond successfully
|
||||
# Scenario: Open source community can find and click on their CTA
|
||||
# Given I am on the "About" page
|
||||
# When I look for the "Join the open source community" CTA
|
||||
# And I click on the "Join the open source community" "external" link
|
||||
# Then the link should respond successfully
|
||||
|
|
|
@ -7,4 +7,5 @@ export const PAGES_ENDPOINTS = {
|
|||
FAQS: '/frequently-asked-questions',
|
||||
PUBLIC_ENG: '/public-engagement',
|
||||
CONTACT: '/contact',
|
||||
PREVIOUS_VERSIONS: '/previous-versions',
|
||||
};
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
Feature: The Methodology page will open from all other pages
|
||||
|
||||
Scenario: Methodology page open when navigating from About page
|
||||
Given I am on the "About" page
|
||||
# When I click on the "Methodology" dropdown in the navigation
|
||||
When I click on the "Methodology" page in the navigation
|
||||
Then I see "Methodology" in the title
|
||||
# Scenario: Methodology page open when navigating from About page
|
||||
# Given I am on the "About" page
|
||||
# # When I click on the "Methodology" dropdown in the navigation
|
||||
# When I click on the "Methodology" page in the navigation
|
||||
# Then I see "Methodology" in the title
|
||||
|
||||
Scenario: Methodology page open when navigating from Explore the map page
|
||||
Given I am on the "Explore" page
|
||||
# When I click on the "Methodology" dropdown in the navigation
|
||||
When I click on the "Methodology" page in the navigation
|
||||
Then I see "Methodology" in the title
|
||||
# Scenario: Methodology page open when navigating from Explore the map page
|
||||
# Given I am on the "Explore" page
|
||||
# # When I click on the "Methodology" dropdown in the navigation
|
||||
# When I click on the "Methodology" page in the navigation
|
||||
# Then I see "Methodology" in the title
|
||||
|
||||
Scenario: Methodology page open when navigating from Contact page
|
||||
Given I am on the "Contact" page
|
||||
# When I click on the "Methodology" dropdown in the navigation
|
||||
When I click on the "Methodology" page in the navigation
|
||||
Then I see "Methodology" in the title
|
||||
# Scenario: Methodology page open when navigating from Contact page
|
||||
# Given I am on the "Contact" page
|
||||
# # When I click on the "Methodology" dropdown in the navigation
|
||||
# When I click on the "Methodology" page in the navigation
|
||||
# Then I see "Methodology" in the title
|
191
client/package-lock.json
generated
191
client/package-lock.json
generated
|
@ -11,7 +11,7 @@
|
|||
"dependencies": {
|
||||
"-": "^0.0.1",
|
||||
"@sentry/gatsby": "^7.7.0",
|
||||
"@trussworks/react-uswds": "^2.9.0",
|
||||
"@trussworks/react-uswds": "^3.1.0",
|
||||
"@turf/bbox": "^6.5.0",
|
||||
"d3-ease": "^3.0.1",
|
||||
"gatsby-plugin-env-variables": "^2.2.0",
|
||||
|
@ -26,8 +26,9 @@
|
|||
"react-helmet": "^6.1.0",
|
||||
"react-intl": "^5.24.7",
|
||||
"react-map-gl": "^6.1.19",
|
||||
"react-tooltip": "^4.2.21",
|
||||
"react-use": "^17.3.2",
|
||||
"uswds": "^2.11.2"
|
||||
"uswds": "^2.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^4.8.2",
|
||||
|
@ -3579,16 +3580,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@trussworks/react-uswds": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@trussworks/react-uswds/-/react-uswds-2.9.0.tgz",
|
||||
"integrity": "sha512-qv5twPgzLJulWsZew3No3W45FTp3WrYGwG/3B+w/mPFuAMHmAX7VAiigmg+k2kHFvrpjyAiKZHREpHyhkZIbig==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@trussworks/react-uswds/-/react-uswds-3.1.0.tgz",
|
||||
"integrity": "sha512-4krdLn8LGgr3EwOsizUF6cBLnwDS6x0WgJjjGk59kNBpgH4qiv8YGzic3HYaVr8xWBq36VpEEfGeQZnjYGMegw==",
|
||||
"engines": {
|
||||
"node": "10.x - 16.x"
|
||||
"node": "10.x - 18.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.x || ^17.x",
|
||||
"react-dom": "^16.x || ^17.x",
|
||||
"uswds": "2.11.2"
|
||||
"uswds": "2.13.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@trysound/sax": {
|
||||
|
@ -6352,9 +6353,9 @@
|
|||
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001319",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz",
|
||||
"integrity": "sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw==",
|
||||
"version": "1.0.30001416",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz",
|
||||
"integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -6622,9 +6623,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/classlist-polyfill": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
|
||||
"integrity": "sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.0.3.tgz",
|
||||
"integrity": "sha512-bDLDUsSg5LYFWsc2hphtG6ulyaCFSupdEBU3wxNECKWHnyPVvY8EB9Wbt9DzWkstWclFZhDaZK/VnEK/DmqE/Q=="
|
||||
},
|
||||
"node_modules/clean-stack": {
|
||||
"version": "2.2.0",
|
||||
|
@ -8877,11 +8878,6 @@
|
|||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.89.tgz",
|
||||
"integrity": "sha512-z1Axg0Fu54fse8wN4fd+GAINdU5mJmLtcl6bqIcYyzNVGONcfHAeeJi88KYMQVKalhXlYuVPzKkFIU5VD0raUw=="
|
||||
},
|
||||
"node_modules/elem-dataset": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/elem-dataset/-/elem-dataset-2.0.0.tgz",
|
||||
"integrity": "sha512-e7gieGopWw5dMdEgythH3lUS7nMizutPDTtkzfQW/q2gCvFnACyNnK3ytCncAXKxdBXQWcXeKaYTTODiMnp8mw=="
|
||||
},
|
||||
"node_modules/element-closest": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/element-closest/-/element-closest-2.0.2.tgz",
|
||||
|
@ -20858,6 +20854,30 @@
|
|||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/react-tooltip": {
|
||||
"version": "4.2.21",
|
||||
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-4.2.21.tgz",
|
||||
"integrity": "sha512-zSLprMymBDowknr0KVDiJ05IjZn9mQhhg4PRsqln0OZtURAJ1snt1xi5daZfagsh6vfsziZrc9pErPTDY1ACig==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"uuid": "^7.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"npm": ">=6.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.0.0",
|
||||
"react-dom": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-tooltip/node_modules/uuid": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
|
||||
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/react-universal-interface": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
|
||||
|
@ -25238,57 +25258,20 @@
|
|||
}
|
||||
},
|
||||
"node_modules/uswds": {
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/uswds/-/uswds-2.11.2.tgz",
|
||||
"integrity": "sha512-JISTXCjPIlrufbObIifjrMDn5jF9bbLu7UYhGWmEs9iqB6Z2KDCXHVoBUyzMmIrIjW/UWWYHZzPqOOHO6/IMCQ==",
|
||||
"version": "2.13.3",
|
||||
"resolved": "https://registry.npmjs.org/uswds/-/uswds-2.13.3.tgz",
|
||||
"integrity": "sha512-qCblljeaRvS3+PrSxoHqQwmMnp746+Y1YZA34BkTzJknvo2bhhdzGE21yJaInumzIqV3glLD13TFdRwrwikMMQ==",
|
||||
"dependencies": {
|
||||
"classlist-polyfill": "^1.0.3",
|
||||
"del": "^6.0.0",
|
||||
"domready": "^1.0.8",
|
||||
"elem-dataset": "^2.0.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"receptor": "^1.0.0",
|
||||
"resolve-id-refs": "^0.1.0"
|
||||
"classlist-polyfill": "1.0.3",
|
||||
"domready": "1.0.8",
|
||||
"object-assign": "4.1.1",
|
||||
"receptor": "1.0.0",
|
||||
"resolve-id-refs": "0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/uswds/node_modules/del": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz",
|
||||
"integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==",
|
||||
"dependencies": {
|
||||
"globby": "^11.0.1",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"is-glob": "^4.0.1",
|
||||
"is-path-cwd": "^2.2.0",
|
||||
"is-path-inside": "^3.0.2",
|
||||
"p-map": "^4.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"slash": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/uswds/node_modules/p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||
"dependencies": {
|
||||
"aggregate-error": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
|
@ -29128,9 +29111,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@trussworks/react-uswds": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@trussworks/react-uswds/-/react-uswds-2.9.0.tgz",
|
||||
"integrity": "sha512-qv5twPgzLJulWsZew3No3W45FTp3WrYGwG/3B+w/mPFuAMHmAX7VAiigmg+k2kHFvrpjyAiKZHREpHyhkZIbig==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@trussworks/react-uswds/-/react-uswds-3.1.0.tgz",
|
||||
"integrity": "sha512-4krdLn8LGgr3EwOsizUF6cBLnwDS6x0WgJjjGk59kNBpgH4qiv8YGzic3HYaVr8xWBq36VpEEfGeQZnjYGMegw==",
|
||||
"requires": {}
|
||||
},
|
||||
"@trysound/sax": {
|
||||
|
@ -31420,9 +31403,9 @@
|
|||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001319",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz",
|
||||
"integrity": "sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw=="
|
||||
"version": "1.0.30001416",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz",
|
||||
"integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA=="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
|
@ -31616,9 +31599,9 @@
|
|||
}
|
||||
},
|
||||
"classlist-polyfill": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
|
||||
"integrity": "sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.0.3.tgz",
|
||||
"integrity": "sha512-bDLDUsSg5LYFWsc2hphtG6ulyaCFSupdEBU3wxNECKWHnyPVvY8EB9Wbt9DzWkstWclFZhDaZK/VnEK/DmqE/Q=="
|
||||
},
|
||||
"clean-stack": {
|
||||
"version": "2.2.0",
|
||||
|
@ -33405,11 +33388,6 @@
|
|||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.89.tgz",
|
||||
"integrity": "sha512-z1Axg0Fu54fse8wN4fd+GAINdU5mJmLtcl6bqIcYyzNVGONcfHAeeJi88KYMQVKalhXlYuVPzKkFIU5VD0raUw=="
|
||||
},
|
||||
"elem-dataset": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/elem-dataset/-/elem-dataset-2.0.0.tgz",
|
||||
"integrity": "sha512-e7gieGopWw5dMdEgythH3lUS7nMizutPDTtkzfQW/q2gCvFnACyNnK3ytCncAXKxdBXQWcXeKaYTTODiMnp8mw=="
|
||||
},
|
||||
"element-closest": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/element-closest/-/element-closest-2.0.2.tgz",
|
||||
|
@ -42347,6 +42325,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"react-tooltip": {
|
||||
"version": "4.2.21",
|
||||
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-4.2.21.tgz",
|
||||
"integrity": "sha512-zSLprMymBDowknr0KVDiJ05IjZn9mQhhg4PRsqln0OZtURAJ1snt1xi5daZfagsh6vfsziZrc9pErPTDY1ACig==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2",
|
||||
"uuid": "^7.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
|
||||
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-universal-interface": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
|
||||
|
@ -45704,42 +45698,15 @@
|
|||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
||||
},
|
||||
"uswds": {
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/uswds/-/uswds-2.11.2.tgz",
|
||||
"integrity": "sha512-JISTXCjPIlrufbObIifjrMDn5jF9bbLu7UYhGWmEs9iqB6Z2KDCXHVoBUyzMmIrIjW/UWWYHZzPqOOHO6/IMCQ==",
|
||||
"version": "2.13.3",
|
||||
"resolved": "https://registry.npmjs.org/uswds/-/uswds-2.13.3.tgz",
|
||||
"integrity": "sha512-qCblljeaRvS3+PrSxoHqQwmMnp746+Y1YZA34BkTzJknvo2bhhdzGE21yJaInumzIqV3glLD13TFdRwrwikMMQ==",
|
||||
"requires": {
|
||||
"classlist-polyfill": "^1.0.3",
|
||||
"del": "^6.0.0",
|
||||
"domready": "^1.0.8",
|
||||
"elem-dataset": "^2.0.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"receptor": "^1.0.0",
|
||||
"resolve-id-refs": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"del": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz",
|
||||
"integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==",
|
||||
"requires": {
|
||||
"globby": "^11.0.1",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"is-glob": "^4.0.1",
|
||||
"is-path-cwd": "^2.2.0",
|
||||
"is-path-inside": "^3.0.2",
|
||||
"p-map": "^4.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||
"requires": {
|
||||
"aggregate-error": "^3.0.0"
|
||||
}
|
||||
}
|
||||
"classlist-polyfill": "1.0.3",
|
||||
"domready": "1.0.8",
|
||||
"object-assign": "4.1.1",
|
||||
"receptor": "1.0.0",
|
||||
"resolve-id-refs": "0.1.0"
|
||||
}
|
||||
},
|
||||
"util": {
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
"intl:compile-en": "formatjs compile src/intl/en.json --ast --out-file compiled-lang/en.json",
|
||||
"test:intl-extraction": "node src/intl/testIntlExtraction",
|
||||
"prepare": "cd .. && husky install client/.husky",
|
||||
"gc": "node .generate_component $1"
|
||||
"gc": "node .generate_component $1",
|
||||
"compile": "tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^4.8.2",
|
||||
|
@ -77,7 +78,7 @@
|
|||
"dependencies": {
|
||||
"-": "^0.0.1",
|
||||
"@sentry/gatsby": "^7.7.0",
|
||||
"@trussworks/react-uswds": "^2.9.0",
|
||||
"@trussworks/react-uswds": "^3.1.0",
|
||||
"@turf/bbox": "^6.5.0",
|
||||
"d3-ease": "^3.0.1",
|
||||
"gatsby-plugin-env-variables": "^2.2.0",
|
||||
|
@ -92,8 +93,9 @@
|
|||
"react-helmet": "^6.1.0",
|
||||
"react-intl": "^5.24.7",
|
||||
"react-map-gl": "^6.1.19",
|
||||
"react-tooltip": "^4.2.21",
|
||||
"react-use": "^17.3.2",
|
||||
"uswds": "^2.11.2"
|
||||
"uswds": "^2.13.3"
|
||||
},
|
||||
"cypress-cucumber-preprocessor": {
|
||||
"nonGlobalStepDefinitions": false
|
||||
|
|
|
@ -59,13 +59,13 @@ const AboutCard = (props: React.PropsWithChildren<AboutCardProps>) => {
|
|||
<h3>{props.header}</h3>
|
||||
{props.children}
|
||||
<div className={'j40-aboutcard-sm-link'}>
|
||||
<LinkTypeWrapper
|
||||
{props.url && <LinkTypeWrapper
|
||||
linkText={props.linkText}
|
||||
internal={props.internal}
|
||||
url={props.url ? props.url : ''}
|
||||
openUrlNewTab={props.openUrlNewTab}
|
||||
className={'j40-aboutcard-link'}
|
||||
/>
|
||||
// className={'j40-aboutcard-link'}
|
||||
/>}
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
|
|
@ -77,7 +77,6 @@ exports[`rendering of the AboutCard checks if small cards component renders 1`]
|
|||
class="j40-aboutcard-sm-link"
|
||||
>
|
||||
<a
|
||||
class="j40-aboutcard-link"
|
||||
data-cy=""
|
||||
href="#"
|
||||
>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,9 +10,10 @@ $sidePanelLabelFontColor: #171716;
|
|||
}
|
||||
|
||||
.versionInfo {
|
||||
padding: .5rem 1rem .5rem 1.2rem;
|
||||
padding: 2rem 1rem 2rem 1.2rem;
|
||||
text-align: center;
|
||||
font-size: medium;
|
||||
border-bottom: 1px solid $sidePanelBorderColor;
|
||||
color: #A0A3A3;
|
||||
}
|
||||
|
||||
.areaDetailContainer {
|
||||
|
@ -24,7 +25,7 @@ $sidePanelLabelFontColor: #171716;
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@include u-padding-bottom(3);
|
||||
// @include u-padding-bottom(3);
|
||||
|
||||
.isInFocus {
|
||||
padding: .5rem 1rem .25rem 1.2rem;
|
||||
|
@ -40,6 +41,14 @@ $sidePanelLabelFontColor: #171716;
|
|||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.prioCopy{
|
||||
@include u-padding-left(2);
|
||||
@include u-padding-right(2);
|
||||
@include u-padding-top(2);
|
||||
|
||||
}
|
||||
|
||||
.showCategoriesExceed {
|
||||
|
@ -47,41 +56,38 @@ $sidePanelLabelFontColor: #171716;
|
|||
@include u-margin-top('05');
|
||||
}
|
||||
|
||||
// .showThresholdExceed {
|
||||
// font-size: small;
|
||||
// @include u-margin-top('05');
|
||||
// }
|
||||
}
|
||||
|
||||
.sendFeedbackLink {
|
||||
@include u-margin-top(2);
|
||||
.sendFeedbackLink {
|
||||
@include u-margin-top(2);
|
||||
@include u-margin-left(2);
|
||||
@include u-margin-bottom(2);
|
||||
|
||||
.sendFeedbackBtn{
|
||||
@include u-text("blue-70v");
|
||||
@include u-bg("yellow-20v");
|
||||
height: 40px;
|
||||
.sendFeedbackBtn{
|
||||
@include u-text("blue-70v");
|
||||
@include u-bg("yellow-20v");
|
||||
height: 40px;
|
||||
|
||||
&:hover {
|
||||
@include u-bg("yellow-20");
|
||||
@include u-text("gray-90");
|
||||
&:hover {
|
||||
@include u-bg("yellow-20");
|
||||
@include u-text("gray-90");
|
||||
}
|
||||
|
||||
.buttonContainer{
|
||||
display: flex;
|
||||
|
||||
.buttonText{
|
||||
@include u-margin-right(1);
|
||||
}
|
||||
|
||||
.buttonContainer{
|
||||
display: flex;
|
||||
.buttonImage{
|
||||
width: 21px;
|
||||
margin-top: -3px;
|
||||
|
||||
.buttonText{
|
||||
@include u-margin-right(1);
|
||||
}
|
||||
|
||||
.buttonImage{
|
||||
width: 21px;
|
||||
margin-top: -3px;
|
||||
|
||||
filter: invert(13%) sepia(76%) saturate(5142%) hue-rotate(192deg) brightness(80%) contrast(106%);
|
||||
}
|
||||
filter: invert(13%) sepia(76%) saturate(5142%) hue-rotate(192deg) brightness(80%) contrast(106%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Census row styles
|
||||
|
@ -112,14 +118,16 @@ $sidePanelLabelFontColor: #171716;
|
|||
}
|
||||
|
||||
.categorySpacer {
|
||||
@include u-bg('gray-cool-3');
|
||||
|
||||
@include typeset('sans', '2xs', 2);
|
||||
@include u-text('bold');
|
||||
|
||||
margin: 0 -20px 1rem -20px;
|
||||
@include u-padding-top(2);
|
||||
@include u-padding-bottom(2);
|
||||
margin-left: -20px;
|
||||
@include u-padding-top(1);
|
||||
@include u-padding-bottom(1);
|
||||
@include u-padding-left(2.5);
|
||||
|
||||
}
|
||||
|
||||
.testSignals{
|
||||
padding-left: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ declare namespace MapModuleScssNamespace {
|
|||
buttonText: string;
|
||||
buttonImage: string;
|
||||
categorySpacer: string;
|
||||
testSignals: string;
|
||||
prioCopy: string;
|
||||
federalRecogTribes: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,68 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import AreaDetail from '..';
|
||||
import {LocalizedComponent} from '../../../test/testHelpers';
|
||||
|
||||
import * as constants from '../../../data/constants';
|
||||
|
||||
describe('rendering of the AreaDetail', () => {
|
||||
const properties = {
|
||||
[constants.POVERTY_BELOW_100_PERCENTILE]: .12,
|
||||
[constants.HIGH_SCHOOL_PROPERTY_PERCENTILE]: .98,
|
||||
[constants.LINGUISTIC_ISOLATION_PROPERTY_PERCENTILE]: .97,
|
||||
[constants.UNEMPLOYMENT_PROPERTY_PERCENTILE]: .96,
|
||||
[constants.HOUSING_BURDEN_PROPERTY_PERCENTILE]: .95,
|
||||
[constants.SCORE_PROPERTY_HIGH]: .95,
|
||||
[constants.GEOID_PROPERTY]: 98729374234,
|
||||
[constants.TOTAL_POPULATION]: 3435435,
|
||||
[constants.STATE_NAME]: 'New York',
|
||||
[constants.COUNTY_NAME]: 'Brooklyn',
|
||||
[constants.POVERTY_BELOW_200_PERCENTILE]: .19,
|
||||
[constants.SIDE_PANEL_STATE]: constants.SIDE_PANEL_STATE_VALUES.NATION,
|
||||
[constants.COUNT_OF_CATEGORIES_DISADV]: 5,
|
||||
[constants.TOTAL_NUMBER_OF_DISADVANTAGE_INDICATORS]: 3,
|
||||
};
|
||||
const hash = ['11.54', '36.0762', '-84.4494'];
|
||||
|
||||
it('checks if indicators for NATION is present', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<AreaDetail properties={properties} hash={hash}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if indicators for PUERTO RICO are present', () => {
|
||||
const propertiesPR = {
|
||||
...properties,
|
||||
[constants.SIDE_PANEL_STATE]: constants.SIDE_PANEL_STATE_VALUES.PUERTO_RICO,
|
||||
};
|
||||
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<AreaDetail properties={propertiesPR} hash={hash}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if indicators for ISLAND AREAS are present', () => {
|
||||
const propertiesIA = {
|
||||
...properties,
|
||||
[constants.ISLAND_AREAS_UNEMPLOYMENT_LOW_HS_EDU_PERCENTILE_FIELD]: .9,
|
||||
[constants.ISLAND_AREAS_POVERTY_LOW_HS_EDU_PERCENTILE_FIELD]: .8,
|
||||
[constants.ISLAND_AREAS_LOW_MEDIAN_INCOME_LOW_HS_EDU_PERCENTILE_FIELD]: .6,
|
||||
[constants.ISLAND_AREAS_POVERTY_LOW_HS_EDU_PERCENTILE_FIELD]: .5,
|
||||
[constants.SIDE_PANEL_STATE]: constants.SIDE_PANEL_STATE_VALUES.ISLAND_AREAS,
|
||||
};
|
||||
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<AreaDetail properties={propertiesIA} hash={hash}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
@include u-bg("gray-cool-2");
|
||||
|
||||
.betaBanner {
|
||||
@include u-display("flex");
|
||||
@include u-height(3);
|
||||
max-width: 70.25rem; // Needs this exact value to align with GovBanner
|
||||
@include u-font("body", "3xs");
|
||||
|
@ -22,17 +21,5 @@
|
|||
@include u-height(6);
|
||||
}
|
||||
|
||||
.betaPillIcon {
|
||||
@include u-bg("yellow-20v");
|
||||
@include u-height(1);
|
||||
@include u-width(2);
|
||||
@include u-radius("2px");
|
||||
@include u-margin-right(1);
|
||||
margin-top: 0.4rem; //Needs this exact value for vertical alignment
|
||||
}
|
||||
|
||||
.betaHeading {
|
||||
@include u-text("bold");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,13 @@
|
|||
import React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
|
||||
import * as COMMON_COPY from '../../data/copy/common';
|
||||
import * as styles from './BetaBanner.module.scss';
|
||||
|
||||
const BetaBanner = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div className={styles.betaBannerContainer}>
|
||||
<div className={styles.betaBanner}>
|
||||
<div className={styles.betaPillIcon}></div>
|
||||
<div>
|
||||
<span className={styles.betaHeading}>
|
||||
{intl.formatMessage(COMMON_COPY.BETA_BANNER.TITLE)}{' '}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage(COMMON_COPY.BETA_BANNER.INFO)}
|
||||
</span>
|
||||
</div>
|
||||
{COMMON_COPY.BETA_BANNER_CONTENT}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -4,16 +4,10 @@ exports[`rendering of the BetaBanner checks if component renders 1`] = `
|
|||
<DocumentFragment>
|
||||
<div>
|
||||
<div>
|
||||
<div />
|
||||
<div>
|
||||
<span>
|
||||
This is a beta site.
|
||||
</span>
|
||||
<span>
|
||||
It is an early, in-progress version of the tool with limited datasets that will
|
||||
be regularly updated.
|
||||
</span>
|
||||
</div>
|
||||
<strong>
|
||||
This tool has been updated.
|
||||
</strong>
|
||||
The 1.0 version of the tool was released on Nov 22, 2022.
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
|
|
|
@ -5,4 +5,9 @@
|
|||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
@include u-margin-top(4);
|
||||
|
||||
.tribalLandsPara {
|
||||
@include u-margin-bottom(6);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
declare namespace CategoriesNamespace {
|
||||
export interface ICategoriesScss {
|
||||
categoriesContainer: string;
|
||||
tribalLandsPara: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {Grid} from '@trussworks/react-uswds';
|
||||
|
||||
import CategoryCard from '../CategoryCard';
|
||||
|
@ -10,22 +11,27 @@ import * as styles from './Categories.module.scss';
|
|||
const categories = [
|
||||
METHODOLOGY_COPY.CATEGORIES.CLIMATE_CHANGE,
|
||||
METHODOLOGY_COPY.CATEGORIES.CLEAN_ENERGY,
|
||||
METHODOLOGY_COPY.CATEGORIES.CLEAN_TRANSPORT,
|
||||
METHODOLOGY_COPY.CATEGORIES.HEALTH_BURDENS,
|
||||
METHODOLOGY_COPY.CATEGORIES.AFFORDABLE_HOUSING,
|
||||
METHODOLOGY_COPY.CATEGORIES.LEGACY_POLLUTION,
|
||||
METHODOLOGY_COPY.CATEGORIES.CLEAN_TRANSPORT,
|
||||
METHODOLOGY_COPY.CATEGORIES.CLEAN_WATER,
|
||||
METHODOLOGY_COPY.CATEGORIES.HEALTH_BURDENS,
|
||||
METHODOLOGY_COPY.CATEGORIES.WORKFORCE_DEV,
|
||||
];
|
||||
|
||||
const Categories = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<>
|
||||
<J40MainGridContainer className={styles.categoriesContainer}>
|
||||
<J40MainGridContainer>
|
||||
|
||||
<Grid row>
|
||||
<Grid col={12}>
|
||||
<Grid col={8}>
|
||||
<h2>{METHODOLOGY_COPY.CATEGORY.HEADING}</h2>
|
||||
<p>{intl.formatMessage(METHODOLOGY_COPY.PAGE.PARA3)}</p>
|
||||
<p>{intl.formatMessage(METHODOLOGY_COPY.PAGE.PARA4)}</p>
|
||||
<p>{METHODOLOGY_COPY.FORMULA.PARA4}</p>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
@ -36,6 +42,18 @@ const Categories = () => {
|
|||
categories.map((category, index) => <CategoryCard key={index} categoryInfo={category} />)
|
||||
}
|
||||
</J40MainGridContainer>
|
||||
|
||||
<J40MainGridContainer>
|
||||
|
||||
<Grid row className={styles.tribalLandsPara}>
|
||||
<Grid col={8}>
|
||||
<h2>{intl.formatMessage(METHODOLOGY_COPY.PAGE.SUB_HEADING_2)}</h2>
|
||||
<p>{intl.formatMessage(METHODOLOGY_COPY.PAGE.PARA5)}</p>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</J40MainGridContainer>
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,12 +11,39 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
data-testid="grid"
|
||||
>
|
||||
<div
|
||||
class="grid-col-12"
|
||||
class="grid-col-8"
|
||||
data-testid="grid"
|
||||
>
|
||||
<h2>
|
||||
Categories
|
||||
Categories of Burdens
|
||||
</h2>
|
||||
<p>
|
||||
|
||||
The tool uses datasets as indicators of burdens. The burdens are organized into categories. A community is highlighted as disadvantaged on the CEJST map if it is in a census tract that is (1) at or above the threshold for one or more environmental, climate, or other burdens, and (2) at or
|
||||
above the threshold for an associated socioeconomic burden.
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
In addition, a census tract that is completely surrounded by disadvantaged communities and is at or above the 50% percentile for low income is also considered disadvantaged.
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Census tracts are small units of geography. Census tract boundaries for
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
data-cy=""
|
||||
href="https://www.census.gov/programs-surveys/geography/about/glossary.html#par_textimage_6"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
statistical areas
|
||||
</a>
|
||||
are determined by the U.S. Census Bureau once every ten years. The tool utilizes the census tract boundaries from 2010. This was chosen because many of the data sources in the tool currently use the 2010
|
||||
census boundaries.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,31 +61,48 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#exp-agr-loss-rate"
|
||||
>
|
||||
expected agriculture loss rate
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#exp-bld-loss-rate"
|
||||
>
|
||||
expected building loss rate
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#exp-pop-loss-rate"
|
||||
>
|
||||
expected population loss rate
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#flood-risk"
|
||||
>
|
||||
projected flood risk
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#wildfire-risk"
|
||||
>
|
||||
projected wildfire risk
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
@ -66,26 +110,20 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Clean energy and energy efficiency
|
||||
Energy
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
|
@ -93,21 +131,23 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#energy-burden"
|
||||
>
|
||||
energy burden
|
||||
energy cost
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#pm-25"
|
||||
>
|
||||
PM2.5 in the air
|
||||
|
@ -119,26 +159,20 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Clean transit
|
||||
Health
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
|
@ -146,23 +180,229 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#asthma"
|
||||
>
|
||||
asthma
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#diabetes"
|
||||
>
|
||||
diabetes
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#heart-disease"
|
||||
>
|
||||
heart disease
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#life-exp"
|
||||
>
|
||||
low life expectancy
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Housing
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
Communities are
|
||||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Experienced
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#hist-underinv"
|
||||
>
|
||||
historic underinvestment
|
||||
</a>
|
||||
OR are at or above the 90th percentile for the
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#house-burden"
|
||||
>
|
||||
housing cost
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#green-space"
|
||||
>
|
||||
lack of green space
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#indoor-plumb"
|
||||
>
|
||||
lack of indoor plumbing
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#lead-paint"
|
||||
>
|
||||
lead paint
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Legacy pollution
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
Communities are
|
||||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Have at least one
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#mine-land"
|
||||
>
|
||||
abandoned mine land
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#fuds"
|
||||
>
|
||||
Formerly Used Defense Sites
|
||||
</a>
|
||||
OR are at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#prox-haz"
|
||||
>
|
||||
proximity to hazardous waste facilities
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#prox-npl"
|
||||
>
|
||||
proximity to Superfind sites (National Priorities List (NPL))
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#prox-rmp"
|
||||
>
|
||||
proximity to Risk Management Plan (RMP) facilities
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Transportation
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
Communities are
|
||||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
IF
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#diesel-pm"
|
||||
>
|
||||
diesel particulate matter exposure
|
||||
</a>
|
||||
or
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#trans-barrier"
|
||||
>
|
||||
transportation barriers
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#traffic-vol"
|
||||
>
|
||||
traffic proximity and volume
|
||||
|
@ -176,26 +416,20 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Affordable and sustainable housing
|
||||
Water and wastewater
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
|
@ -203,133 +437,23 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
href="#lead-paint"
|
||||
class="usa-link"
|
||||
href="#leaky-uwt"
|
||||
>
|
||||
lead paint
|
||||
</a>
|
||||
AND
|
||||
<a
|
||||
href="#median-home"
|
||||
>
|
||||
median home value
|
||||
</a>
|
||||
is at or less than the 90th percentile OR at or above the 90th percentile for the
|
||||
<a
|
||||
href="#house-burden"
|
||||
>
|
||||
housing cost burden
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
<a
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Reduction and remediation of legacy pollution
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
Communities are
|
||||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
href="#prox-haz"
|
||||
>
|
||||
proximity to hazardous waste facilities
|
||||
underground storage tanks and releases
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
href="#prox-npl"
|
||||
>
|
||||
proximity to National Priorities List (NPL) sites
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
href="#prox-rmp"
|
||||
>
|
||||
proximity to Risk Management Plan (RMP) facilities
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
<a
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Critical clean water and wastewater infrastructure
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
Communities are
|
||||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#waste-water"
|
||||
>
|
||||
wastewater discharge
|
||||
|
@ -341,26 +465,20 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Health burdens
|
||||
Workforce development
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
|
@ -368,125 +486,85 @@ exports[`rendering of the Categories checks if component renders 1`] = `
|
|||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
IF
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
href="#asthma"
|
||||
>
|
||||
asthma
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
href="#diabetes"
|
||||
>
|
||||
diabetes
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
href="#heart-disease"
|
||||
>
|
||||
heart disease
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
href="#life-exp"
|
||||
>
|
||||
low life expectancy
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
<a
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Training and workforce development
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
Communities are
|
||||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
href="#low-med-inc"
|
||||
>
|
||||
low median income
|
||||
</a>
|
||||
as a percentage of area median income OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#ling-iso"
|
||||
>
|
||||
linguistic isolation
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
href="#unemploy"
|
||||
class="usa-link"
|
||||
href="#low-med-inc"
|
||||
>
|
||||
unemployment
|
||||
low median income
|
||||
</a>
|
||||
OR percentage of individuals in households at or below 100% Federal
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#poverty"
|
||||
>
|
||||
poverty
|
||||
</a>
|
||||
level
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#unemploy"
|
||||
>
|
||||
unemployment
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
10% or more of adults 25 or older have not attained a
|
||||
fewer than 10% of people ages 25 or older have a
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#high-school"
|
||||
>
|
||||
high school degree
|
||||
high school education
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
(i.e. graduated with a high school degree)
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid-container-desktop-lg"
|
||||
data-testid="gridContainer"
|
||||
>
|
||||
<div
|
||||
class="grid-row"
|
||||
data-testid="grid"
|
||||
>
|
||||
<div
|
||||
class="grid-col-8"
|
||||
data-testid="grid"
|
||||
>
|
||||
<h2>
|
||||
|
||||
Tribes
|
||||
|
||||
</h2>
|
||||
<p>
|
||||
|
||||
Federally Recognized Tribes, including Alaska Native Villages, are also considered disadvantaged communities.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
|
|
|
@ -8,3 +8,12 @@
|
|||
flex-basis: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.disCategoryContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.category {
|
||||
flex-basis: 80%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ declare namespace CategoryNamespace {
|
|||
export interface ICategoryScss {
|
||||
categoryContainer: string;
|
||||
category:string;
|
||||
disadvantageDot: string;
|
||||
disCategoryContainer: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,35 @@ import * as styles from './Category.module.scss';
|
|||
|
||||
interface ICategory {
|
||||
name: string;
|
||||
isDisadvantaged: boolean;
|
||||
isDisadvantaged: boolean | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This component controls the Categories on the side panel.
|
||||
*
|
||||
* The category will be styled differently differently depending on
|
||||
* if the category is disadvantaged or not. The JSX in the return
|
||||
* statement is identical however in the global CSS file, we
|
||||
* override the disadvantaged case with a psuedo-selector (:has) that
|
||||
* is new. In order to fallback gracefully for browsers that do
|
||||
* not yet support the ":has" psuedo selector, this redundant JSX
|
||||
* will allow the disadvantaged case show the older category styling
|
||||
* while browsers that do support the ":has" psuedo selector will
|
||||
* render the newer category style.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {boolean} isDisadvagtaged
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
const Category = ({name, isDisadvantaged}:ICategory) => {
|
||||
return (
|
||||
return isDisadvantaged ? (
|
||||
<div className={styles.disCategoryContainer}>
|
||||
<div className={styles.category}>
|
||||
{name}
|
||||
</div>
|
||||
<DisadvantageDot isDisadvantaged={isDisadvantaged}/>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.categoryContainer}>
|
||||
<div className={styles.category}>
|
||||
{name}
|
||||
|
@ -18,5 +42,4 @@ const Category = ({name, isDisadvantaged}:ICategory) => {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Category;
|
||||
|
|
|
@ -6,8 +6,7 @@ interface ICategoryInterface {
|
|||
categoryInfo: {
|
||||
TITLE: JSX.Element,
|
||||
IF: JSX.Element,
|
||||
AND: JSX.Element,
|
||||
THEN: JSX.Element
|
||||
AND: JSX.Element
|
||||
}
|
||||
}
|
||||
const CategoryCard = ({categoryInfo}: ICategoryInterface) => {
|
||||
|
@ -25,9 +24,6 @@ const CategoryCard = ({categoryInfo}: ICategoryInterface) => {
|
|||
<p>
|
||||
{categoryInfo.AND}
|
||||
</p>
|
||||
<p>
|
||||
{categoryInfo.THEN}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,31 +12,48 @@ exports[`rendering of the CategoryCard checks if component renders 1`] = `
|
|||
<strong>
|
||||
identified as disadvantaged
|
||||
</strong>
|
||||
|
||||
if they are in census tracts that:
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
IF
|
||||
ARE
|
||||
</strong>
|
||||
at or above the 90th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#exp-agr-loss-rate"
|
||||
>
|
||||
expected agriculture loss rate
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#exp-bld-loss-rate"
|
||||
>
|
||||
expected building loss rate
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#exp-pop-loss-rate"
|
||||
>
|
||||
expected population loss rate
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#flood-risk"
|
||||
>
|
||||
projected flood risk
|
||||
</a>
|
||||
OR
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#wildfire-risk"
|
||||
>
|
||||
projected wildfire risk
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
|
@ -44,22 +61,16 @@ exports[`rendering of the CategoryCard checks if component renders 1`] = `
|
|||
<strong>
|
||||
AND
|
||||
</strong>
|
||||
is at or above the 65th percentile for
|
||||
are at or above the 65th percentile for
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#low-income"
|
||||
>
|
||||
low income
|
||||
</a>
|
||||
AND 80% or more of individuals 15 or older are not enrolled in
|
||||
<a
|
||||
href="#high-ed-enroll-rate"
|
||||
>
|
||||
higher education
|
||||
</a>
|
||||
|
||||
|
||||
</p>
|
||||
<p />
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable valid-jsdoc */
|
||||
import React from 'react';
|
||||
import {Tag} from '@trussworks/react-uswds';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
|
||||
import * as styles from './datasetCard.module.scss';
|
||||
|
@ -17,11 +18,21 @@ interface IDatasetCardProps {
|
|||
*/
|
||||
const DatasetCard = ({datasetCardProps}: IDatasetCardProps) => {
|
||||
const intl = useIntl();
|
||||
const isNoteAtEnd = datasetCardProps.domID === 'ling-iso' ? true : false;
|
||||
|
||||
return (
|
||||
<div className={styles.datasetCard} id={datasetCardProps.domID}>
|
||||
{/* Dataset header */}
|
||||
<h3 className={styles.datasetCardIndicator}>{datasetCardProps.indicator}</h3>
|
||||
<div className={datasetCardProps.isNew ? styles.datasetCardHeader : ''}>
|
||||
{datasetCardProps.isNew &&
|
||||
<div className={styles.tagContainer}>
|
||||
<Tag className={styles.newTag}>{intl.formatMessage(METHODOLOGY_COPY.DATASET_CARD_LABELS.NEW)}</Tag>
|
||||
</div>
|
||||
}
|
||||
<h3 className={styles.datasetCardIndicator}>
|
||||
{datasetCardProps.indicator}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* Dataset description */}
|
||||
<div className={styles.datasetCardDescription}>
|
||||
|
@ -29,7 +40,7 @@ const DatasetCard = ({datasetCardProps}: IDatasetCardProps) => {
|
|||
</div>
|
||||
|
||||
{/* Dataset note */}
|
||||
{datasetCardProps.note && <div className={styles.datasetCardDescription}>
|
||||
{(datasetCardProps.note && !isNoteAtEnd) && <div className={styles.datasetCardDescription}>
|
||||
<p>{datasetCardProps.note}</p>
|
||||
</div>}
|
||||
|
||||
|
@ -73,6 +84,11 @@ const DatasetCard = ({datasetCardProps}: IDatasetCardProps) => {
|
|||
))}
|
||||
|
||||
</ul>
|
||||
|
||||
{/* Dataset note */}
|
||||
{(datasetCardProps.note && isNoteAtEnd) && <div className={styles.datasetCardDescription}>
|
||||
<p>{datasetCardProps.note}</p>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -57,3 +57,18 @@
|
|||
font-size: large;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.datasetCardHeader{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tagContainer {
|
||||
@include u-margin-right(1);
|
||||
@include u-margin-top("05");
|
||||
}
|
||||
|
||||
.newTag {
|
||||
@include u-bg('yellow-20v');
|
||||
@include u-text('blue-70v');
|
||||
font-weight: bolder;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
declare namespace DatasetCardScssNamespace {
|
||||
export interface IDatasetCardScss {
|
||||
datasetCard: string;
|
||||
datasetCardHeader: string;
|
||||
datasetCardAdditional:string;
|
||||
datasetCardIndicator:string;
|
||||
datasetCardWhatIsIt: string;
|
||||
|
@ -9,6 +10,8 @@ declare namespace DatasetCardScssNamespace {
|
|||
datasetCardList: string;
|
||||
datasetCardListItemSource: string;
|
||||
datasetCardListItem: string;
|
||||
newTag: string;
|
||||
tagContainer: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,17 @@ exports[`rendering of indicator dataset card checks if component renders 1`] = `
|
|||
<div
|
||||
id="low-income"
|
||||
>
|
||||
<h3>
|
||||
Low income
|
||||
</h3>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<h3>
|
||||
Low income
|
||||
</h3>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
Percent of a census tract's population in households where household income is at or below
|
||||
200% of the Federal poverty level.
|
||||
200% of the Federal poverty level, not including students enrolled in higher education.
|
||||
|
||||
</div>
|
||||
<ul>
|
||||
|
@ -25,7 +29,7 @@ exports[`rendering of indicator dataset card checks if component renders 1`] = `
|
|||
<span>
|
||||
Responsible Party:
|
||||
</span>
|
||||
Census
|
||||
U.S. Census
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
|
@ -46,7 +50,7 @@ exports[`rendering of indicator dataset card checks if component renders 1`] = `
|
|||
<span>
|
||||
Available for:
|
||||
</span>
|
||||
All U.S. states and the District of Columbia
|
||||
All U.S. states, the District of Columbia, and Puerto Rico
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -9,6 +9,7 @@ import {hyphenizeString} from '../../../cypress/integration/common/helpers';
|
|||
import * as styles from './dsContainer.module.scss';
|
||||
import * as METHODOLOGY_COPY from '../../data/copy/methodology';
|
||||
import {PAGES_ENDPOINTS} from '../../data/constants';
|
||||
import DatasetsButton from '../DatasetsButton';
|
||||
|
||||
|
||||
const DatasetContainer = () => {
|
||||
|
@ -22,14 +23,19 @@ const DatasetContainer = () => {
|
|||
|
||||
<Grid row>
|
||||
<Grid col={12}>
|
||||
<h2>{intl.formatMessage(METHODOLOGY_COPY.DATASETS.HEADING)}</h2>
|
||||
<h2>{METHODOLOGY_COPY.DATASETS_RICH_TEXT.HEADING}</h2>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid row>
|
||||
<Grid desktop={{col: 9}}>
|
||||
<Grid row gap>
|
||||
<Grid desktop={{col: 7}}>
|
||||
<p>{intl.formatMessage(METHODOLOGY_COPY.DATASETS.INFO)}</p>
|
||||
</Grid>
|
||||
<Grid desktop={{col: 1}}>
|
||||
</Grid>
|
||||
<Grid desktop={{col: 4}}>
|
||||
<DatasetsButton href= {'https://www.surveymonkey.com/r/6G9TQJ8'} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid row>
|
||||
|
@ -44,7 +50,7 @@ const DatasetContainer = () => {
|
|||
</Grid>
|
||||
|
||||
<div className={styles.returnToTop}>
|
||||
<Link to={PAGES_ENDPOINTS.METHODOLOGY}>
|
||||
<Link className={'usa-link'} to={PAGES_ENDPOINTS.METHODOLOGY}>
|
||||
{METHODOLOGY_COPY.RETURN_TO_TOP.LINK}
|
||||
</Link>
|
||||
</div>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,25 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
|
||||
.datasetsButtonContainer{
|
||||
@include u-margin-top(3);
|
||||
|
||||
@include u-height(6);
|
||||
z-index: 2;
|
||||
|
||||
@include u-text("blue-70v");
|
||||
@include u-bg("yellow-20v");
|
||||
|
||||
&:hover {
|
||||
@include u-bg("yellow-20");
|
||||
@include u-text("gray-90");
|
||||
}
|
||||
|
||||
.launchIcon {
|
||||
height: .8rem;
|
||||
|
||||
// Change color of USWDS icon
|
||||
filter: invert(13%) sepia(76%) saturate(5142%) hue-rotate(192deg) brightness(80%) contrast(106%);
|
||||
}
|
||||
}
|
||||
|
||||
|
13
client/src/components/DatasetsButton/DatasetsButton.module.scss.d.ts
vendored
Normal file
13
client/src/components/DatasetsButton/DatasetsButton.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
declare namespace DatasetsButtonNamespace {
|
||||
export interface IDatasetsButtonScss {
|
||||
datasetsButtonContainer: string;
|
||||
launchIcon: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const DatasetsButtonScssModule: DatasetsButtonNamespace.IDatasetsButtonScss & {
|
||||
/** WARNING: Only available when "css-loader" is used without "style-loader" or "mini-css-extract-plugin" */
|
||||
locals: DatasetsButtonNamespace.IDatasetsButtonScss;
|
||||
};
|
||||
|
||||
export = DatasetsButtonScssModule;
|
15
client/src/components/DatasetsButton/DatasetsButton.test.tsx
Normal file
15
client/src/components/DatasetsButton/DatasetsButton.test.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../test/testHelpers';
|
||||
import DatasetsButton from './DatasetsButton';
|
||||
|
||||
describe('rendering of DatasetsButton Component', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<DatasetsButton />
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
it('checks if component renders', () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
34
client/src/components/DatasetsButton/DatasetsButton.tsx
Normal file
34
client/src/components/DatasetsButton/DatasetsButton.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {Button} from '@trussworks/react-uswds';
|
||||
|
||||
import * as styles from './DatasetsButton.module.scss';
|
||||
import * as METHODOLOGY_COPY from '../../data/copy/methodology';
|
||||
|
||||
// @ts-ignore
|
||||
import launchIcon from '/node_modules/uswds/dist/img/usa-icons/launch.svg';
|
||||
|
||||
export interface IDatasetsButtonProps {
|
||||
href: string,
|
||||
}
|
||||
|
||||
const DatasetsButton = ({href}: IDatasetsButtonProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<a href={href} target='_blank' rel="noreferrer">
|
||||
<Button
|
||||
type="button"
|
||||
className={styles.datasetsButtonContainer}>
|
||||
{intl.formatMessage(METHODOLOGY_COPY.DATASETS.BUTTON_TEXT)}
|
||||
<img
|
||||
className={styles.launchIcon}
|
||||
src={launchIcon}
|
||||
alt={'launch icon'}
|
||||
/>
|
||||
</Button>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default DatasetsButton;
|
|
@ -0,0 +1,22 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of DatasetsButton Component checks if component renders 1`] = `
|
||||
<DocumentFragment>
|
||||
<a
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<button
|
||||
class="usa-button"
|
||||
data-testid="button"
|
||||
type="button"
|
||||
>
|
||||
Share data sources with CEQ
|
||||
<img
|
||||
alt="launch icon"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
</button>
|
||||
</a>
|
||||
</DocumentFragment>
|
||||
`;
|
2
client/src/components/DatasetsButton/index.ts
Normal file
2
client/src/components/DatasetsButton/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import DatasetsButton from './DatasetsButton';
|
||||
export default DatasetsButton;
|
|
@ -1,4 +1,5 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
@import "../utils.scss";
|
||||
|
||||
.disadvantagedDotSmall {
|
||||
@include u-circle('105');
|
||||
|
@ -12,7 +13,7 @@
|
|||
@include u-circle(4);
|
||||
margin: 2.3rem 1.5rem 2rem 0;
|
||||
// opacity: .6;
|
||||
border: 3px solid #1A4480;
|
||||
border: 3px solid $disadvantagedDotColor;
|
||||
|
||||
//Maintain aspect ratio as screen width decreases
|
||||
flex: 1 0 2rem;
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import * as styles from './DisadvantageDot.module.scss';
|
||||
|
||||
interface IDisadvantageDot {
|
||||
isDisadvantaged?: boolean;
|
||||
isDisadvantaged?: boolean | null;
|
||||
isBig?: boolean;
|
||||
}
|
||||
const DisadvantageDot = ({isDisadvantaged = false, isBig}:IDisadvantageDot) => {
|
||||
|
|
40
client/src/components/DonutCopy/DonutCopy.module.scss
Normal file
40
client/src/components/DonutCopy/DonutCopy.module.scss
Normal file
|
@ -0,0 +1,40 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
@import "../utils.scss";
|
||||
|
||||
.donutCopyContainer{
|
||||
@include u-display('flex');
|
||||
flex-direction: column;
|
||||
@include u-padding-left(2);
|
||||
@include u-padding-right(2.5);
|
||||
@include u-padding-top(2);
|
||||
|
||||
.donutRow {
|
||||
@include u-display('flex');
|
||||
justify-content: space-between;
|
||||
|
||||
.donutRowLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.valueSubTextContainer {
|
||||
@include u-display('flex');
|
||||
flex-direction: column;
|
||||
.subTextContainer{
|
||||
@include indicatorValueSubTextContainer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.donutRow:first-child {
|
||||
@include u-padding-bottom("05");
|
||||
}
|
||||
|
||||
.invert {
|
||||
align-self: flex-end;
|
||||
@include invert();
|
||||
}
|
||||
|
||||
.noInvert {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
18
client/src/components/DonutCopy/DonutCopy.module.scss.d.ts
vendored
Normal file
18
client/src/components/DonutCopy/DonutCopy.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
declare namespace DonutCopyNamespace {
|
||||
export interface IDonutCopyScss {
|
||||
donutCopyContainer: string;
|
||||
donutRow: string;
|
||||
donutRowLabel: string;
|
||||
invert: string;
|
||||
noInvert: string;
|
||||
valueSubTextContainer: string;
|
||||
subTextContainer: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const DonutCopyScssModule: DonutCopyNamespace.IDonutCopyScss & {
|
||||
/** WARNING: Only available when "css-loader" is used without "style-loader" or "mini-css-extract-plugin" */
|
||||
locals: DonutCopyNamespace.IDonutCopyScss;
|
||||
};
|
||||
|
||||
export = DonutCopyScssModule;
|
29
client/src/components/DonutCopy/DonutCopy.test.tsx
Normal file
29
client/src/components/DonutCopy/DonutCopy.test.tsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../test/testHelpers';
|
||||
import DonutCopy from './DonutCopy';
|
||||
|
||||
describe('rendering of DonutCopy Component', () => {
|
||||
it('checks if component renders when adjacency is false', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<DonutCopy
|
||||
isAdjacent={false}
|
||||
povertyBelow200Percentile={32}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
it('checks if component renders when adjacency is false', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<DonutCopy
|
||||
isAdjacent={true}
|
||||
povertyBelow200Percentile={32}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
54
client/src/components/DonutCopy/DonutCopy.tsx
Normal file
54
client/src/components/DonutCopy/DonutCopy.tsx
Normal file
|
@ -0,0 +1,54 @@
|
|||
import React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
|
||||
import {IndicatorValue, IndicatorValueSubText} from '../Indicator/Indicator';
|
||||
|
||||
import * as styles from './DonutCopy.module.scss';
|
||||
|
||||
import * as EXPLORE_COPY from '../../data/copy/explore';
|
||||
|
||||
export interface IDonutCopyProps {
|
||||
isAdjacent: boolean
|
||||
povertyBelow200Percentile: number | null
|
||||
}
|
||||
|
||||
const DonutCopy = ({isAdjacent, povertyBelow200Percentile}: IDonutCopyProps) => {
|
||||
const intl = useIntl();
|
||||
const povBel200Percentile = povertyBelow200Percentile ?
|
||||
parseFloat((povertyBelow200Percentile*100).toFixed()) : null;
|
||||
const threshold = 50;
|
||||
|
||||
return (
|
||||
<div className={styles.donutCopyContainer}>
|
||||
<div className={styles.donutRow}>
|
||||
<div className={styles.donutRowLabel}>{intl.formatMessage(EXPLORE_COPY.DONUT_COPY.COMP_SURR)}</div>
|
||||
<div className={isAdjacent ? styles.invert : ''}>
|
||||
{isAdjacent ? EXPLORE_COPY.COMMUNITY.OF_FOCUS : EXPLORE_COPY.COMMUNITY.NOT_OF_FOCUS}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.donutRow}>
|
||||
<div className={styles.donutRowLabel}>{intl.formatMessage(EXPLORE_COPY.DONUT_COPY.ADJ_LOW_INC)}</div>
|
||||
<div className={styles.valueSubTextContainer}>
|
||||
<div className={
|
||||
isAdjacent && povBel200Percentile &&
|
||||
povBel200Percentile >= threshold ? styles.invert : styles.noInvert}>
|
||||
<IndicatorValue
|
||||
type={'percentile'}
|
||||
displayStat={povBel200Percentile}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.subTextContainer}>
|
||||
<IndicatorValueSubText
|
||||
value={povBel200Percentile}
|
||||
isAboveThresh={povBel200Percentile && povBel200Percentile >= threshold ? true : false}
|
||||
threshold={threshold}
|
||||
type={'percentile'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DonutCopy;
|
|
@ -0,0 +1,85 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of DonutCopy Component checks if component renders when adjacency is false 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
Completely surrounded
|
||||
</div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
No
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
Adjusted low income
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
3
|
||||
<sup
|
||||
style="top: -0.2em;"
|
||||
>
|
||||
th
|
||||
</sup>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
above 50
|
||||
<sup
|
||||
style="top: -0.2em;"
|
||||
>
|
||||
th
|
||||
</sup>
|
||||
percentile
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`rendering of DonutCopy Component checks if component renders when adjacency is false 2`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
Completely surrounded
|
||||
</div>
|
||||
<div>
|
||||
YES
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
Adjusted low income
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
3
|
||||
<sup
|
||||
style="top: -0.2em;"
|
||||
>
|
||||
th
|
||||
</sup>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
above 50
|
||||
<sup
|
||||
style="top: -0.2em;"
|
||||
>
|
||||
th
|
||||
</sup>
|
||||
percentile
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
2
client/src/components/DonutCopy/index.ts
Normal file
2
client/src/components/DonutCopy/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import DonutCopy from './DonutCopy';
|
||||
export default DonutCopy;
|
|
@ -0,0 +1,64 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
|
||||
@mixin buttonImageBase {
|
||||
width: 21px;
|
||||
margin-top: -3px;
|
||||
};
|
||||
|
||||
@mixin downloadButtonBase {
|
||||
height: 40px;
|
||||
@include u-margin-top(3);
|
||||
|
||||
.buttonContainer {
|
||||
display: flex;
|
||||
|
||||
.buttonText {
|
||||
@include u-margin-right(1);
|
||||
}
|
||||
|
||||
.buttonImageYellow {
|
||||
@include buttonImageBase();
|
||||
filter: invert(13%) sepia(76%) saturate(5142%) hue-rotate(192deg) brightness(80%) contrast(106%);
|
||||
}
|
||||
|
||||
.buttonImageGray {
|
||||
@include buttonImageBase();
|
||||
filter: invert(100%) sepia(0%) saturate(7489%) hue-rotate(232deg) brightness(101%) contrast(101%);
|
||||
}
|
||||
|
||||
.buttonImageBlue {
|
||||
@include buttonImageBase();
|
||||
filter: invert(100%) sepia(100%) saturate(1%) hue-rotate(137deg) brightness(103%) contrast(101%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.downloadButtonLink{
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
justify-content: center;
|
||||
|
||||
.buttonComponentYellow {
|
||||
@include downloadButtonBase;
|
||||
@include u-text("blue-70v");
|
||||
@include u-bg("yellow-20v");
|
||||
&:hover {
|
||||
@include u-bg("yellow-20");
|
||||
@include u-text("gray-90");
|
||||
}
|
||||
}
|
||||
|
||||
.buttonComponentGray {
|
||||
@include downloadButtonBase;
|
||||
@include u-text("white");
|
||||
@include u-bg("gray-60");
|
||||
&:hover {
|
||||
@include u-bg("gray-90");
|
||||
@include u-text("gray-10");
|
||||
}
|
||||
}
|
||||
|
||||
.buttonComponent {
|
||||
@include downloadButtonBase;
|
||||
}
|
||||
}
|
20
client/src/components/DownloadButton/DownloadButton.module.scss.d.ts
vendored
Normal file
20
client/src/components/DownloadButton/DownloadButton.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
declare namespace DownloadButtonNamespace {
|
||||
export interface IDownloadButtonScss {
|
||||
downloadButtonLink: string;
|
||||
buttonComponent: string;
|
||||
buttonComponentYellow: string;
|
||||
buttonComponentGray: string;
|
||||
buttonContainer: string;
|
||||
buttonText: string;
|
||||
buttonImageBlue: string;
|
||||
buttonImageYellow: string;
|
||||
buttonImageGray: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const DownloadButtonScssModule: DownloadButtonNamespace.IDownloadButtonScss & {
|
||||
/** WARNING: Only available when "css-loader" is used without "style-loader" or "mini-css-extract-plugin" */
|
||||
locals: DownloadButtonNamespace.IDownloadButtonScss;
|
||||
};
|
||||
|
||||
export = DownloadButtonScssModule;
|
19
client/src/components/DownloadButton/DownloadButton.test.tsx
Normal file
19
client/src/components/DownloadButton/DownloadButton.test.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../test/testHelpers';
|
||||
import DownloadButton from './DownloadButton';
|
||||
|
||||
describe('rendering of DownloadButton Component', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<DownloadButton
|
||||
downloadLink='https://google.com'
|
||||
buttonText='Hello'
|
||||
imageAltTagText='download button'
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
it('checks if component renders', () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
43
client/src/components/DownloadButton/DownloadButton.tsx
Normal file
43
client/src/components/DownloadButton/DownloadButton.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
import {Button} from '@trussworks/react-uswds';
|
||||
|
||||
import * as styles from './DownloadButton.module.scss';
|
||||
// @ts-ignore
|
||||
import fileDownloadIcon from '/node_modules/uswds/dist/img/usa-icons/file_download.svg';
|
||||
|
||||
export interface IDownloadButtonProps {
|
||||
downloadLink: string,
|
||||
buttonText: string
|
||||
imageAltTagText: string,
|
||||
color : 'gray' | 'yellow' | 'default'
|
||||
}
|
||||
|
||||
const DownloadButton = ({downloadLink, buttonText, imageAltTagText, color}: IDownloadButtonProps) => {
|
||||
return (
|
||||
<a className={styles.downloadButtonLink} href={downloadLink} download>
|
||||
<Button
|
||||
type="button"
|
||||
className={
|
||||
color === 'yellow' ? styles.buttonComponentYellow :
|
||||
color === 'gray' ? styles.buttonComponentGray :
|
||||
styles.buttonComponent
|
||||
}>
|
||||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.buttonText}>
|
||||
{buttonText}
|
||||
</div>
|
||||
<img
|
||||
className={
|
||||
color === 'yellow' ? styles.buttonImageYellow :
|
||||
color === 'gray' ? styles.buttonImageGray :
|
||||
styles.buttonImageBlue}
|
||||
src={fileDownloadIcon}
|
||||
alt={imageAltTagText}
|
||||
/>
|
||||
</div>
|
||||
</Button>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default DownloadButton;
|
|
@ -0,0 +1,26 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of DownloadButton Component checks if component renders 1`] = `
|
||||
<DocumentFragment>
|
||||
<a
|
||||
download=""
|
||||
href="https://google.com"
|
||||
>
|
||||
<button
|
||||
class="usa-button"
|
||||
data-testid="button"
|
||||
type="button"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
Hello
|
||||
</div>
|
||||
<img
|
||||
alt="download button"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</a>
|
||||
</DocumentFragment>
|
||||
`;
|
2
client/src/components/DownloadButton/index.ts
Normal file
2
client/src/components/DownloadButton/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import DownloadButton from './DownloadButton';
|
||||
export default DownloadButton;
|
|
@ -27,7 +27,7 @@ const DownloadLink = ({href, linkText}:IDownloadLink) => {
|
|||
}
|
||||
return (
|
||||
<>
|
||||
<a href={href} download>{linkText}</a>
|
||||
<a href={href} className={`usa-link`} download>{linkText}</a>
|
||||
<img
|
||||
className={styles.downloadIcon}
|
||||
src={fileDownloadIcon}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
exports[`rendering of the DownloadLink disadvantaged checks if component renders 1`] = `
|
||||
<DocumentFragment>
|
||||
<a
|
||||
class="usa-link"
|
||||
download=""
|
||||
href="https://google.com"
|
||||
>
|
||||
|
|
|
@ -5,7 +5,7 @@ import * as EXPLORE_COPY from '../../data/copy/explore';
|
|||
|
||||
interface IExceedBurden {
|
||||
text: React.ReactElement;
|
||||
isBurdened: boolean;
|
||||
isBurdened: boolean | null;
|
||||
}
|
||||
const ExceedBurden = ({text, isBurdened}:IExceedBurden) => {
|
||||
return (
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
|
||||
.summaryBoxContainer{
|
||||
|
||||
@include u-margin-top(2.5);
|
||||
|
||||
.fileDownIcon{
|
||||
margin-bottom: -4px;
|
||||
@include u-padding-left(1);
|
||||
}
|
||||
}
|
13
client/src/components/ExploreDataBox/ExploreDataBox.module.scss.d.ts
vendored
Normal file
13
client/src/components/ExploreDataBox/ExploreDataBox.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
declare namespace ExploreDataBoxNamespace {
|
||||
export interface IExploreDataBoxScss {
|
||||
summaryBoxContainer: string;
|
||||
fileDownIcon: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const ExploreDataBoxScssModule: ExploreDataBoxNamespace.IExploreDataBoxScss & {
|
||||
/** WARNING: Only available when "css-loader" is used without "style-loader" or "mini-css-extract-plugin" */
|
||||
locals: ExploreDataBoxNamespace.IExploreDataBoxScss;
|
||||
};
|
||||
|
||||
export = ExploreDataBoxScssModule;
|
15
client/src/components/ExploreDataBox/ExploreDataBox.test.tsx
Normal file
15
client/src/components/ExploreDataBox/ExploreDataBox.test.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../test/testHelpers';
|
||||
import ExploreDataBox from './ExploreDataBox';
|
||||
|
||||
describe('rendering of ExploreDataBox Component', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<ExploreDataBox />
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
it('checks if component renders', () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
36
client/src/components/ExploreDataBox/ExploreDataBox.tsx
Normal file
36
client/src/components/ExploreDataBox/ExploreDataBox.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import React from 'react';
|
||||
import {SummaryBox, SummaryBoxContent, SummaryBoxHeading} from '@trussworks/react-uswds';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
|
||||
import * as EXPLORE_COPY from '../../data/copy/explore';
|
||||
|
||||
import * as styles from './ExploreDataBox.module.scss';
|
||||
|
||||
// @ts-ignore
|
||||
import fileDownIcon from '/node_modules/uswds/dist/img/usa-icons/file_download.svg';
|
||||
|
||||
|
||||
export interface IExploreDataBoxProps {}
|
||||
|
||||
const ExploreDataBox = ({}: IExploreDataBoxProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<SummaryBox className={styles.summaryBoxContainer}>
|
||||
|
||||
<SummaryBoxHeading headingLevel='h2'>
|
||||
{intl.formatMessage(EXPLORE_COPY.EXPLORE_DATA_BOX.TITLE)}
|
||||
<img tabIndex={0} className={styles.fileDownIcon} src={fileDownIcon}
|
||||
alt={intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INIT_STATE_ICON_ALT_TEXT.PLUS)}
|
||||
/>
|
||||
</SummaryBoxHeading>
|
||||
|
||||
<SummaryBoxContent>
|
||||
{EXPLORE_COPY.EXPLORE_DATA_BOX_BODY}
|
||||
</SummaryBoxContent>
|
||||
|
||||
</SummaryBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExploreDataBox;
|
|
@ -0,0 +1,41 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of ExploreDataBox Component checks if component renders 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="usa-summary-box"
|
||||
data-testid="summary-box"
|
||||
>
|
||||
<div
|
||||
class="usa-summary-box__body"
|
||||
>
|
||||
<h2
|
||||
class="usa-summary-box__heading"
|
||||
>
|
||||
Get the data
|
||||
<img
|
||||
alt="
|
||||
a plus icon indicating that the user can zoom in
|
||||
*"
|
||||
src="test-file-stub"
|
||||
tabindex="0"
|
||||
/>
|
||||
</h2>
|
||||
<div
|
||||
class="usa-summary-box__text"
|
||||
>
|
||||
|
||||
Download the data with documentation and shapefile from the
|
||||
<a
|
||||
class="usa-link"
|
||||
href="/en/downloads"
|
||||
>
|
||||
downloads
|
||||
</a>
|
||||
page.
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
2
client/src/components/ExploreDataBox/index.ts
Normal file
2
client/src/components/ExploreDataBox/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import ExploreDataBox from './ExploreDataBox';
|
||||
export default ExploreDataBox;
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import {GovBanner} from '@trussworks/react-uswds';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
|
||||
import Language from '../Language';
|
||||
// import Language from '../Language';
|
||||
|
||||
import * as styles from './GovernmentBanner.module.scss';
|
||||
|
||||
|
@ -14,7 +14,8 @@ const GovernmentBanner = () => {
|
|||
<div className={styles.bannerContainer}>
|
||||
|
||||
<GovBanner language={intl.locale === 'es' ? 'spanish' : 'english'}/>
|
||||
<Language isDesktop={true}/>
|
||||
{/* Temporarily removing while language is translated */}
|
||||
{/* <Language isDesktop={true}/> */}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -135,22 +135,6 @@ exports[`rendering of the GovernmentBanner checks if component renders 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div>
|
||||
<img
|
||||
alt="language icon for selecting language"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
English
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
Español
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
import React from 'react';
|
||||
|
||||
import * as styles from './howYouCanHelp.module.scss';
|
||||
import * as EXPLORE_COPY from '../../data/copy/explore';
|
||||
import * as ABOUT_COPY from '../../data/copy/about';
|
||||
|
||||
const HowYouCanHelp = () => {
|
||||
return (
|
||||
<div className={styles.howYouCanHelpContainer}>
|
||||
<h2>
|
||||
{EXPLORE_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.HEADING}
|
||||
{ABOUT_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.HEADING}
|
||||
</h2>
|
||||
<ul className={styles.howYouCanHelpListWrapper}>
|
||||
<li className={styles.howYouCanHelpList}>
|
||||
{EXPLORE_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_1}
|
||||
{ABOUT_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_1}
|
||||
</li>
|
||||
<li className={styles.howYouCanHelpList}>
|
||||
{EXPLORE_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_2}
|
||||
{ABOUT_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_2}
|
||||
</li>
|
||||
{/* <li className={styles.howYouCanHelpList}>
|
||||
{ABOUT_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_3}
|
||||
</li> */}
|
||||
<li className={styles.howYouCanHelpList}>
|
||||
{EXPLORE_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_3}
|
||||
{ABOUT_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.LIST_ITEM_4}
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
{ABOUT_COPY.HOW_YOU_CAN_HELP_LIST_ITEMS.PARA1}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,31 +8,56 @@ exports[`rendering of the HowYouCanHelp checks if various text fields are visibl
|
|||
</h2>
|
||||
<ul>
|
||||
<li>
|
||||
View the
|
||||
<a
|
||||
href="/en/methodology"
|
||||
>
|
||||
Methodology & data
|
||||
</a>
|
||||
page and send feedback.
|
||||
</li>
|
||||
<li>
|
||||
Use the map to find communities and
|
||||
Provide
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
data-cy=""
|
||||
href="mailto:Screeningtool-Support@omb.eop.gov"
|
||||
href="https://www.surveymonkey.com/r/P3LWTSB"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
share your feedback
|
||||
general feedback
|
||||
</a>
|
||||
on the CEJST website
|
||||
</li>
|
||||
<li>
|
||||
Suggest new
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
data-cy=""
|
||||
href="https://www.surveymonkey.com/r/6G9TQJ8"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
data sources
|
||||
</a>
|
||||
.
|
||||
</li>
|
||||
<li>
|
||||
The Request for Information on the Federal Register is now closed.
|
||||
Any other questions? The best way to contact the Council on Environmental Quality (CEQ) is by filling out this
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
data-cy=""
|
||||
href="https://www.surveymonkey.com/r/5LZ7MNB"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
form
|
||||
</a>
|
||||
. Otherwise, email:
|
||||
<a
|
||||
class="usa-link"
|
||||
href="/en/methodology"
|
||||
>
|
||||
Screeningtool-Support@omb.eop.gov
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
The Council on Environmental Quality plans to issue a Request for Information in 2023. This will give the public time to use the tool before providing comments.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
@import "../utils.scss";
|
||||
|
||||
@mixin indicatorPadding {
|
||||
@include u-padding-left("05");
|
||||
@include u-padding-right("05");
|
||||
}
|
||||
|
||||
@mixin indicator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -19,12 +24,11 @@
|
|||
}
|
||||
|
||||
.indicatorName {
|
||||
// flex: 0 1 77%;
|
||||
flex-basis: 60%;
|
||||
flex-basis: 55%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@include typeset('sans', '2xs', 2);
|
||||
@include u-text('medium');
|
||||
@include u-text('bold');
|
||||
|
||||
.indicatorDesc {
|
||||
@include typeset('sans', '3xs', 2);
|
||||
|
@ -40,38 +44,43 @@
|
|||
.indicatorValueCol {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@include typeset('sans', '2xs', 2);
|
||||
@include u-text('bold');
|
||||
width: 40%;
|
||||
|
||||
.indicatorValueRow {
|
||||
display: flex;
|
||||
align-self: end;
|
||||
|
||||
.indicatorValue {
|
||||
margin-left: 2.2rem;
|
||||
@include indicatorPadding();
|
||||
}
|
||||
|
||||
.indicatorArrow {
|
||||
.disIndicatorValue {
|
||||
@include indicatorPadding();
|
||||
color: white;
|
||||
background-color: $disadvantagedDotColor;
|
||||
}
|
||||
|
||||
.indicatorInfo {
|
||||
margin-bottom: -.375rem;
|
||||
margin-top: -2px;
|
||||
@include u-margin-right('05');
|
||||
|
||||
img {
|
||||
img.info {
|
||||
max-width: none;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
|
||||
height: 1.2rem;
|
||||
width: 1.2rem;
|
||||
}
|
||||
.unavailable {
|
||||
opacity: .2;
|
||||
|
||||
.infoTilde {
|
||||
vertical-align: super;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.indicatorValueSubText{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
@include u-width(8);
|
||||
@include typeset('sans', '3xs', 2);
|
||||
@include u-text('thin');
|
||||
@include indicatorValueSubTextContainer();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,31 +90,5 @@
|
|||
//Indicator box styles
|
||||
.indicatorBoxMain {
|
||||
@include indicator;
|
||||
}
|
||||
|
||||
.disadvantagedIndicator {
|
||||
@include indicator;
|
||||
@include u-bg('blue-warm-10');
|
||||
|
||||
// A darker bg color:
|
||||
// background-color: #D2DAE3;
|
||||
|
||||
// Add a border
|
||||
// border: 1px solid #1A4480;
|
||||
|
||||
margin: 0 -20px 1px -20px;
|
||||
@include u-padding-left(2.5);
|
||||
@include u-padding-right(2.5);
|
||||
|
||||
|
||||
// Overwrite indicator mixin with bolder fonts for disadv. indicator
|
||||
.indicatorRow {
|
||||
.indicatorName {
|
||||
@include u-text('bold');
|
||||
|
||||
.indicatorDesc {
|
||||
@include u-text('normal');
|
||||
}
|
||||
}
|
||||
}
|
||||
@include u-color('gray-warm-90');
|
||||
}
|
|
@ -7,9 +7,11 @@ declare namespace IndicatorNamespace {
|
|||
indicatorValueCol:string;
|
||||
indicatorValueRow:string;
|
||||
indicatorValue:string;
|
||||
disIndicatorValue:string;
|
||||
indicatorSuperscript:string;
|
||||
indicatorArrow:string;
|
||||
unavailable:string;
|
||||
indicatorInfo:string;
|
||||
info:string;
|
||||
infoTilde: string;
|
||||
indicatorValueSubText:string;
|
||||
indicatorDesc:string;
|
||||
disadvantagedIndicator:string;
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
import * as React from 'react';
|
||||
import {render, screen} from '@testing-library/react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../test/testHelpers';
|
||||
import Indicator, {IndicatorValueIcon, IndicatorValueSubText, IndicatorValue} from './Indicator';
|
||||
import Indicator, {IndicatorValueSubText, IndicatorValue} from './Indicator';
|
||||
import {indicatorInfo} from '../AreaDetail/AreaDetail';
|
||||
|
||||
import * as EXPLORE_COPY from '../../data/copy/explore';
|
||||
|
||||
|
||||
describe('rendering of the Indicator', () => {
|
||||
it('checks if component renders', () => {
|
||||
const highSchool:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'percent',
|
||||
value: .97,
|
||||
isDisadvagtaged: true,
|
||||
isPercent: true,
|
||||
threshold: 20,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
|
@ -31,9 +28,9 @@ describe('rendering of the Indicator', () => {
|
|||
const highSchool:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'percent',
|
||||
value: .426,
|
||||
isDisadvagtaged: true,
|
||||
isPercent: true,
|
||||
threshold: 20,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
|
@ -47,58 +44,19 @@ describe('rendering of the Indicator', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('test rendering of Indicator value icons', () => {
|
||||
it('renders the up arrow when value is above threshold', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValueIcon
|
||||
value={90}
|
||||
isAboveThresh={true}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
screen.getByAltText(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.ARROW_UP.defaultMessage);
|
||||
});
|
||||
it('renders the down arrow when the value is above the threshold', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValueIcon
|
||||
value={13}
|
||||
isAboveThresh={false}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
screen.getByAltText(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.ARROW_DOWN.defaultMessage);
|
||||
});
|
||||
|
||||
it('renders the down arrow when the value is zero', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValueIcon
|
||||
value={0}
|
||||
isAboveThresh={false}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
screen.getByAltText(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.ARROW_DOWN.defaultMessage);
|
||||
});
|
||||
|
||||
it('renders the unavailable icon when the value is null', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValueIcon
|
||||
value={null}
|
||||
isAboveThresh={false}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
screen.getByAltText(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.UNAVAILABLE.defaultMessage);
|
||||
});
|
||||
});
|
||||
// describe('test rendering of Indicator value icons', () => {
|
||||
// it('renders the unavailable icon when the value is null', () => {
|
||||
// const {asFragment} = render(
|
||||
// <LocalizedComponent>
|
||||
// <IndicatorValueIcon
|
||||
// value={null}
|
||||
// />
|
||||
// </LocalizedComponent>,
|
||||
// );
|
||||
// expect(asFragment()).toMatchSnapshot();
|
||||
// screen.getByAltText(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.UNAVAILABLE.defaultMessage);
|
||||
// });
|
||||
// });
|
||||
|
||||
describe('test rendering of Indicator value sub-text', () => {
|
||||
it('renders the "above 90 percentile"', () => {
|
||||
|
@ -108,7 +66,7 @@ describe('test rendering of Indicator value sub-text', () => {
|
|||
value={95}
|
||||
isAboveThresh={true}
|
||||
threshold={90}
|
||||
isPercent={false}
|
||||
type='percentile'
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
|
@ -121,20 +79,20 @@ describe('test rendering of Indicator value sub-text', () => {
|
|||
value={89}
|
||||
isAboveThresh={false}
|
||||
threshold={90}
|
||||
isPercent={false}
|
||||
type='percentile'
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
it('renders the "data is not available"', () => {
|
||||
it(`renders missing data `, () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValueSubText
|
||||
value={null}
|
||||
isAboveThresh={false}
|
||||
threshold={90}
|
||||
isPercent={false}
|
||||
type='percentile'
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
|
@ -144,58 +102,34 @@ describe('test rendering of Indicator value sub-text', () => {
|
|||
|
||||
describe('test that the unit suffix renders correctly', ()=> {
|
||||
it('renders correctly when the value is a percentile', () => {
|
||||
const lowLife:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
value: 97,
|
||||
isDisadvagtaged: true,
|
||||
isPercent: false,
|
||||
threshold: 20,
|
||||
};
|
||||
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValue
|
||||
isPercent={lowLife.isPercent}
|
||||
type={'percentile'}
|
||||
displayStat={90}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly when the value is a percent', () => {
|
||||
const lowLife:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
value: 97,
|
||||
isDisadvagtaged: true,
|
||||
isPercent: true,
|
||||
threshold: 20,
|
||||
};
|
||||
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValue
|
||||
isPercent={lowLife.isPercent}
|
||||
type={'percent'}
|
||||
displayStat={90}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
it('renders correctly when the value is a null', () => {
|
||||
const lowLife:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
value: null,
|
||||
isDisadvagtaged: true,
|
||||
isPercent: false,
|
||||
};
|
||||
|
||||
it('renders correctly when the value is a null', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<IndicatorValue
|
||||
isPercent={lowLife.isPercent}
|
||||
type={'percentile'}
|
||||
displayStat={null}
|
||||
/>
|
||||
</LocalizedComponent>,
|
||||
|
@ -203,3 +137,153 @@ describe('test that the unit suffix renders correctly', ()=> {
|
|||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('renders value correctly for historic underinvest.', () => {
|
||||
it('checks if it renders when HRS_ET = true', () => {
|
||||
const historicUnderinvest:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={historicUnderinvest}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if it renders when HRS_ET = false:', () => {
|
||||
const historicUnderinvest:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={historicUnderinvest}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if it renders nothin when HRS_ET = null:', () => {
|
||||
const historicUnderinvest:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: null,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={historicUnderinvest}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('renders value correctly for abandoned land mines', () => {
|
||||
it('checks if it renders when AML_RAW = true', () => {
|
||||
const abandonMines:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={abandonMines}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if it renders when AML_RAW = false:', () => {
|
||||
const abandonMines:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={abandonMines}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if it renders nothin when AML_RAW = null:', () => {
|
||||
const abandonMines:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: null,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={abandonMines}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('renders value correctly for Former defense sites', () => {
|
||||
it('checks if it renders when FUDS_RAW = true', () => {
|
||||
const formerDefSites:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: true,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={formerDefSites}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if it renders when FUDS_RAW = false:', () => {
|
||||
const formerDefSites:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={formerDefSites}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if it renders nothin when FUDS_RAW = null:', () => {
|
||||
const formerDefSites:indicatorInfo = {
|
||||
label: 'some label',
|
||||
description: 'some description',
|
||||
type: 'boolean',
|
||||
value: null,
|
||||
isDisadvagtaged: true,
|
||||
};
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<Indicator indicator={formerDefSites}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,66 +1,81 @@
|
|||
import React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
|
||||
import {indicatorInfo} from '../AreaDetail/AreaDetail';
|
||||
import {indicatorInfo, indicatorType} from '../AreaDetail/AreaDetail';
|
||||
|
||||
import * as styles from './Indicator.module.scss';
|
||||
import * as constants from '../../data/constants';
|
||||
import * as EXPLORE_COPY from '../../data/copy/explore';
|
||||
|
||||
// @ts-ignore
|
||||
import downArrow from '/node_modules/uswds/dist/img/usa-icons/arrow_downward.svg';
|
||||
// @ts-ignore
|
||||
import upArrow from '/node_modules/uswds/dist/img/usa-icons/arrow_upward.svg';
|
||||
// @ts-ignore
|
||||
import unAvailable from '/node_modules/uswds/dist/img/usa-icons/do_not_disturb.svg';
|
||||
import infoIcon from '/node_modules/uswds/dist/img/usa-icons/info.svg';
|
||||
|
||||
interface IIndicator {
|
||||
indicator: indicatorInfo,
|
||||
indicator: indicatorInfo,
|
||||
isImpute?: boolean,
|
||||
population?: number | string,
|
||||
}
|
||||
|
||||
interface IIndicatorValueIcon {
|
||||
value: number | null,
|
||||
isAboveThresh: boolean,
|
||||
};
|
||||
|
||||
interface IIndicatorValueSubText {
|
||||
value: number | null,
|
||||
type: indicatorType,
|
||||
value: number | null | boolean,
|
||||
isAboveThresh: boolean,
|
||||
threshold: number,
|
||||
isPercent: boolean | undefined,
|
||||
}
|
||||
|
||||
interface IIndicatorValue {
|
||||
isPercent: boolean | undefined,
|
||||
type: indicatorType,
|
||||
displayStat: number | null,
|
||||
}
|
||||
|
||||
/**
|
||||
* This component will determine what indicator's icon should be (arrowUp, arrowDown or unavailable) and
|
||||
* return the appropriate JSX.
|
||||
* This component will render an info icon in the indicator value
|
||||
*
|
||||
* @param {number | null} props
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
export const IndicatorValueIcon = ({value, isAboveThresh}: IIndicatorValueIcon) => {
|
||||
export const IndicatorInfoIcon = ({isImpute, population}: Omit<IIndicator, 'indicator'>) => {
|
||||
const intl = useIntl();
|
||||
let showTilde = false;
|
||||
|
||||
if (value == null) {
|
||||
return <img className={styles.unavailable}
|
||||
src={unAvailable}
|
||||
alt={intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.UNAVAILABLE)}
|
||||
/>;
|
||||
} else {
|
||||
return isAboveThresh ?
|
||||
const getToolTipCopy = () => {
|
||||
if (population === constants.MISSING_DATA_STRING) {
|
||||
return intl.formatMessage(EXPLORE_COPY.LOW_INCOME_TOOLTIP.IMP_YES_POP_NULL);
|
||||
} else if (population !== constants.MISSING_DATA_STRING && isImpute) {
|
||||
showTilde = true;
|
||||
return intl.formatMessage(EXPLORE_COPY.LOW_INCOME_TOOLTIP.IMP_YES_POP_NOT_NULL);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This library react-tooltip creates random DOM ID which will not allow for snapshot testing as
|
||||
* the IDs change on each build. Due to time constraints, we simply removed the AreaDetails test.
|
||||
* The AreaDetails component is made up of sub component and each sub component has tests so this
|
||||
* is low risk.
|
||||
*
|
||||
* This is a temporary solution. Some longer terms solutions may be
|
||||
* 1. Remove this library and get the USWDS tool tip to work
|
||||
* 2. Re-factor the areaDetail.tests.tsx snapshot tests to do more DOM assertions rather than snapshots
|
||||
* 3. Some combination of the two.
|
||||
*/
|
||||
return (
|
||||
<>
|
||||
<ReactTooltip
|
||||
id="lowIncomeIcon"
|
||||
multiline={true}
|
||||
/>
|
||||
<img
|
||||
src={upArrow}
|
||||
alt={intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.ARROW_UP)}
|
||||
/> :
|
||||
<img
|
||||
src={downArrow}
|
||||
alt={intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.ARROW_DOWN)}
|
||||
/>;
|
||||
}
|
||||
data-for="lowIncomeIcon"
|
||||
data-tip={getToolTipCopy()}
|
||||
data-iscapture="true"
|
||||
className={styles.info}
|
||||
src={infoIcon}
|
||||
alt={intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_VALUES.IMG_ALT_TEXT.INFO)}
|
||||
/>
|
||||
{showTilde && <span className={styles.infoTilde}>{ ` ~ ` }</span>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -69,32 +84,40 @@ export const IndicatorValueIcon = ({value, isAboveThresh}: IIndicatorValueIcon)
|
|||
* "below 20 percent"
|
||||
* "data is not available"
|
||||
*
|
||||
* Todo: refactor into single component, add to i18n and add to tests
|
||||
*
|
||||
* @param {IIndicatorValueSubText} {}
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
export const IndicatorValueSubText = ({value, isAboveThresh, threshold, isPercent}:IIndicatorValueSubText) => {
|
||||
return value == null ?
|
||||
<div>
|
||||
{EXPLORE_COPY.SIDE_PANEL_VALUES.UNAVAILBLE_MSG}
|
||||
</div> :
|
||||
<div>
|
||||
{
|
||||
isAboveThresh ?
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.ABOVE :
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.BELOW
|
||||
}
|
||||
{threshold ?
|
||||
<IndicatorValue isPercent={isPercent} displayStat={threshold} /> :
|
||||
<IndicatorValue isPercent={isPercent} displayStat={90} />
|
||||
}
|
||||
{` `}
|
||||
{
|
||||
isPercent ?
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.PERCENT :
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.PERCENTILE
|
||||
}
|
||||
</div>;
|
||||
export const IndicatorValueSubText = ({type, value, isAboveThresh, threshold}:IIndicatorValueSubText) => {
|
||||
if (value === null) {
|
||||
return (
|
||||
<div>
|
||||
{EXPLORE_COPY.SIDE_PANEL_VALUES.UNAVAILBLE_MSG}
|
||||
</div>
|
||||
);
|
||||
} else if (type === 'percent' || type === 'percentile') {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
isAboveThresh ?
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.ABOVE :
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.BELOW
|
||||
}
|
||||
{
|
||||
threshold ?
|
||||
<IndicatorValue type={type} displayStat={threshold}/> :
|
||||
<IndicatorValue type={type} displayStat={90}/>
|
||||
}
|
||||
{` `}
|
||||
{
|
||||
type === 'percent' ?
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.PERCENT :
|
||||
EXPLORE_COPY.SIDE_PANEL_VALUES.PERCENTILE
|
||||
}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (<></>);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -138,46 +161,61 @@ export const superscriptOrdinal = (indicatorValueWithSuffix:string) => {
|
|||
};
|
||||
|
||||
/**
|
||||
* This component will return the indicators's value with an ordinal suffix
|
||||
* or a percentage sign using i18n functions
|
||||
* This component will return the indicators's value. The value depends on the
|
||||
* indicator type. Each type renders a different UI.
|
||||
*
|
||||
* @return {JSX.Element | null}
|
||||
*/
|
||||
export const IndicatorValue = ({isPercent, displayStat}:IIndicatorValue) => {
|
||||
export const IndicatorValue = ({type, displayStat}:IIndicatorValue) => {
|
||||
const intl = useIntl();
|
||||
|
||||
if (displayStat === null) return <React.Fragment></React.Fragment>;
|
||||
if (displayStat === null) return <>{constants.MISSING_DATA_STRING}</>;
|
||||
|
||||
const i18nOrdinalSuffix: string = intl.formatMessage(
|
||||
{
|
||||
id: 'explore.map.page.side.panel.indicator.percentile.value.ordinal.suffix',
|
||||
// eslint-disable-next-line max-len
|
||||
description: `Navigate to the explore the tool page. Click on the map. The side panel will show categories. Open a category. This will define the indicator value's ordinal suffix. For example the st in 91st, the rd in 23rd, and the th in 26th, etc.`,
|
||||
defaultMessage: `
|
||||
if (type === 'percent' || type === 'percentile') {
|
||||
// In this case we will show no value and an icon only
|
||||
|
||||
if (type === 'percent') {
|
||||
// If the type is percent, return the intl percent format
|
||||
return (
|
||||
<span>
|
||||
{intl.formatNumber(
|
||||
displayStat,
|
||||
{
|
||||
style: 'unit',
|
||||
unit: 'percent',
|
||||
unitDisplay: 'short',
|
||||
},
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
// If the type is percentile, create the intl ordinal and return it as a superscript
|
||||
const i18nOrdinalSuffix: string = intl.formatMessage(
|
||||
{
|
||||
id: 'explore.map.page.side.panel.indicator.percentile.value.ordinal.suffix',
|
||||
// eslint-disable-next-line max-len
|
||||
description: `Navigate to the explore the tool page. Click on the map. The side panel will show categories. Open a category. This will define the indicator value's ordinal suffix. For example the st in 91st, the rd in 23rd, and the th in 26th, etc.`,
|
||||
defaultMessage: `
|
||||
{indicatorValue, selectordinal,
|
||||
one {#st}
|
||||
two {#nd}
|
||||
=3 {#rd}
|
||||
other {#th}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
indicatorValue: displayStat,
|
||||
},
|
||||
);
|
||||
|
||||
return isPercent ?
|
||||
<span>
|
||||
{intl.formatNumber(
|
||||
displayStat,
|
||||
{
|
||||
style: 'unit',
|
||||
unit: 'percent',
|
||||
unitDisplay: 'short',
|
||||
}
|
||||
`,
|
||||
},
|
||||
)}
|
||||
</span> : superscriptOrdinal(i18nOrdinalSuffix);
|
||||
{
|
||||
indicatorValue: displayStat,
|
||||
},
|
||||
);
|
||||
return superscriptOrdinal(i18nOrdinalSuffix);
|
||||
}
|
||||
} else {
|
||||
// when the type === boolean the display stat will be either 100 (true) or 0 (false)
|
||||
return displayStat === 0 ?
|
||||
EXPLORE_COPY.SIDE_PANEL_SPACERS.NO :
|
||||
EXPLORE_COPY.SIDE_PANEL_SPACERS.YES;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -186,9 +224,17 @@ export const IndicatorValue = ({isPercent, displayStat}:IIndicatorValue) => {
|
|||
* @param {IIndicator} indicator
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
const Indicator = ({indicator}:IIndicator) => {
|
||||
// Convert the decimal value to a stat to display
|
||||
const displayStat = indicator.value !== null ? Math.floor(indicator.value * 100) : null;
|
||||
const Indicator = ({indicator, isImpute, population}:IIndicator) => {
|
||||
/**
|
||||
* The indicator value could be a number | boolean | null. In all cases we coerce to number
|
||||
* before flooring.
|
||||
*
|
||||
* In the case where indicator.value is a boolean, the displayStat will be either 100 or 0, depending
|
||||
* on if indicator.value is true or false respectively.
|
||||
*
|
||||
* Todo: The way the displayStat handles the boolean indicators should be refactored
|
||||
*/
|
||||
const displayStat = indicator.value !== null ? Math.floor(Number(indicator.value) * 100) : null;
|
||||
|
||||
// If the threshold exists, set it, otherwise set it to the default value
|
||||
const threshold = indicator.threshold ? indicator.threshold : constants.DEFAULT_THRESHOLD_PERCENTILE;
|
||||
|
@ -196,10 +242,15 @@ const Indicator = ({indicator}:IIndicator) => {
|
|||
// A boolean to represent if the indicator is above or below the threshold
|
||||
const isAboveThresh = displayStat !== null && displayStat >= threshold ? true : false;
|
||||
|
||||
// Show an info icon on the low icome indicator if:
|
||||
const showLowIncomeInfoIcon = (
|
||||
(indicator.label === 'Low income' && (isImpute)) ||
|
||||
(indicator.label === 'Low income' && population === constants.MISSING_DATA_STRING && !isImpute)
|
||||
);
|
||||
|
||||
return (
|
||||
<li
|
||||
className={indicator.isDisadvagtaged ? styles.disadvantagedIndicator : styles.indicatorBoxMain}
|
||||
className={styles.indicatorBoxMain}
|
||||
data-cy={'indicatorBox'}
|
||||
data-testid='indicator-box'>
|
||||
<div className={styles.indicatorRow}>
|
||||
|
@ -216,18 +267,26 @@ const Indicator = ({indicator}:IIndicator) => {
|
|||
<div className={styles.indicatorValueCol}>
|
||||
<div className={styles.indicatorValueRow}>
|
||||
|
||||
{/* Indicator value */}
|
||||
<div className={styles.indicatorValue}>
|
||||
<IndicatorValue isPercent={indicator.isPercent} displayStat={displayStat}/>
|
||||
</div>
|
||||
{/* Indicator info icon */}
|
||||
{ showLowIncomeInfoIcon &&
|
||||
<div className={styles.indicatorInfo}>
|
||||
<IndicatorInfoIcon
|
||||
isImpute={isImpute}
|
||||
population={population}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* Indicator icon - up arrow, down arrow, or unavailable */}
|
||||
<div className={styles.indicatorArrow}>
|
||||
<IndicatorValueIcon
|
||||
value={displayStat}
|
||||
isAboveThresh={isAboveThresh}
|
||||
{/* Indicator value */}
|
||||
<div className={indicator.isDisadvagtaged ?
|
||||
styles.disIndicatorValue : styles.indicatorValue}
|
||||
>
|
||||
<IndicatorValue
|
||||
type={indicator.type}
|
||||
displayStat={displayStat}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Indicator sub-text */}
|
||||
|
@ -236,9 +295,10 @@ const Indicator = ({indicator}:IIndicator) => {
|
|||
value={displayStat}
|
||||
isAboveThresh={isAboveThresh}
|
||||
threshold={threshold}
|
||||
isPercent={indicator.isPercent}
|
||||
type={indicator.type}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
|
|
@ -20,12 +20,6 @@ exports[`rendering of the Indicator checks if component renders 1`] = `
|
|||
97%
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<img
|
||||
alt="an icon for the up arrow"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
|
@ -62,12 +56,6 @@ exports[`rendering of the Indicator checks if the flooring function works 1`] =
|
|||
42%
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<img
|
||||
alt="an icon for the up arrow"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
|
@ -84,39 +72,257 @@ exports[`rendering of the Indicator checks if the flooring function works 1`] =
|
|||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test rendering of Indicator value icons renders the down arrow when the value is above the threshold 1`] = `
|
||||
exports[`renders value correctly for Former defense sites checks if it renders nothin when FUDS_RAW = null: 1`] = `
|
||||
<DocumentFragment>
|
||||
<img
|
||||
alt="an icon for the down arrow"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
--
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
missing data
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test rendering of Indicator value icons renders the down arrow when the value is zero 1`] = `
|
||||
exports[`renders value correctly for Former defense sites checks if it renders when FUDS_RAW = false: 1`] = `
|
||||
<DocumentFragment>
|
||||
<img
|
||||
alt="an icon for the down arrow"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
No
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test rendering of Indicator value icons renders the unavailable icon when the value is null 1`] = `
|
||||
exports[`renders value correctly for Former defense sites checks if it renders when FUDS_RAW = true 1`] = `
|
||||
<DocumentFragment>
|
||||
<img
|
||||
alt="an icon to represent data is unavailable"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
Yes
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test rendering of Indicator value icons renders the up arrow when value is above threshold 1`] = `
|
||||
exports[`renders value correctly for abandoned land mines checks if it renders nothin when AML_RAW = null: 1`] = `
|
||||
<DocumentFragment>
|
||||
<img
|
||||
alt="an icon for the up arrow"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
--
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
missing data
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`renders value correctly for abandoned land mines checks if it renders when AML_RAW = false: 1`] = `
|
||||
<DocumentFragment>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
No
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`renders value correctly for abandoned land mines checks if it renders when AML_RAW = true 1`] = `
|
||||
<DocumentFragment>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
Yes
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`renders value correctly for historic underinvest. checks if it renders nothin when HRS_ET = null: 1`] = `
|
||||
<DocumentFragment>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
--
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
missing data
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`renders value correctly for historic underinvest. checks if it renders when HRS_ET = false: 1`] = `
|
||||
<DocumentFragment>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
No
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`renders value correctly for historic underinvest. checks if it renders when HRS_ET = true 1`] = `
|
||||
<DocumentFragment>
|
||||
<li
|
||||
data-cy="indicatorBox"
|
||||
data-testid="indicator-box"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
some label
|
||||
<div>
|
||||
some description
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
Yes
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test rendering of Indicator value sub-text renders missing data 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
missing data
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
|
@ -148,16 +354,12 @@ exports[`test rendering of Indicator value sub-text renders the "below 90 percen
|
|||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test rendering of Indicator value sub-text renders the "data is not available" 1`] = `
|
||||
exports[`test that the unit suffix renders correctly renders correctly when the value is a null 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
data is not available
|
||||
</div>
|
||||
--
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`test that the unit suffix renders correctly renders correctly when the value is a null 1`] = `<DocumentFragment />`;
|
||||
|
||||
exports[`test that the unit suffix renders correctly renders correctly when the value is a percent 1`] = `
|
||||
<DocumentFragment>
|
||||
<span>
|
||||
|
|
|
@ -13,7 +13,6 @@ import SurveyButton from '../SurveyButton';
|
|||
|
||||
// @ts-ignore
|
||||
import whitehouseIcon from '../../images/eop-seal.svg';
|
||||
import {PAGES_ENDPOINTS} from '../../data/constants';
|
||||
import * as COMMON_COPY from '../../data/copy/common';
|
||||
|
||||
const J40Footer = () => {
|
||||
|
@ -33,27 +32,19 @@ const J40Footer = () => {
|
|||
COMMON_COPY.FOOTER_CEQ_ADDRESS.PHONE,
|
||||
]}
|
||||
/>,
|
||||
<LinkTypeWrapper
|
||||
linkText={intl.formatMessage(COMMON_COPY.FOOTER.SIGN_UP)}
|
||||
internal={false}
|
||||
url={COMMON_COPY.FOOTER.SIGN_UP_LINK}
|
||||
openUrlNewTab={true}
|
||||
key={'signup'}
|
||||
dataCy={hyphenizeString(COMMON_COPY.FOOTER.SIGN_UP.defaultMessage)}
|
||||
/>,
|
||||
],
|
||||
[
|
||||
intl.formatMessage(COMMON_COPY.FOOTER.MORE_INFO),
|
||||
<LinkTypeWrapper
|
||||
linkText={intl.formatMessage(COMMON_COPY.FOOTER.ENG_CAL)}
|
||||
internal={true}
|
||||
url={PAGES_ENDPOINTS.PUBLIC_ENG}
|
||||
openUrlNewTab={false}
|
||||
className={'footer-link-first-child'}
|
||||
key={'publiceng'}
|
||||
dataCy={hyphenizeString(COMMON_COPY.FOOTER.ENG_CAL.defaultMessage)}
|
||||
/>,
|
||||
<LinkTypeWrapper
|
||||
linkText={intl.formatMessage(COMMON_COPY.FOOTER.RFI)}
|
||||
internal={false}
|
||||
url={intl.formatMessage(COMMON_COPY.FOOTER.RFI_LINK)}
|
||||
openUrlNewTab={true}
|
||||
key={'rfilink'}
|
||||
dataCy={hyphenizeString(COMMON_COPY.FOOTER.RFI.defaultMessage)}
|
||||
/>,
|
||||
<LinkTypeWrapper
|
||||
linkText={intl.formatMessage(COMMON_COPY.FOOTER.WHITEHOUSE)}
|
||||
internal={false}
|
||||
url={intl.formatMessage(COMMON_COPY.FOOTER.WHITEHOUSE_LINK)}
|
||||
|
|
|
@ -60,6 +60,19 @@ exports[`J40Footer renders correctly 1`] = `
|
|||
</div>
|
||||
</address>
|
||||
</li>
|
||||
<li
|
||||
class="usa-footer__secondary-link"
|
||||
>
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
data-cy="sign-up-for-updates"
|
||||
href="https://lp.constantcontactpages.com/su/Vm8pCFj/spring"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Sign up for updates
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -79,30 +92,7 @@ exports[`J40Footer renders correctly 1`] = `
|
|||
class="usa-footer__secondary-link"
|
||||
>
|
||||
<a
|
||||
class="footer-link-first-child"
|
||||
href="/en/public-engagement"
|
||||
>
|
||||
Engagement calendar
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="usa-footer__secondary-link"
|
||||
>
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
data-cy="request-for-information"
|
||||
href="https://www.federalregister.gov/d/2022-03920"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Request for Information
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="usa-footer__secondary-link"
|
||||
>
|
||||
<a
|
||||
class="usa-link usa-link--external"
|
||||
class="usa-link usa-link--external footer-link-first-child"
|
||||
data-cy="whitehouse-gov"
|
||||
href="https://www.whitehouse.gov/"
|
||||
rel="noreferrer"
|
||||
|
@ -221,7 +211,7 @@ exports[`J40Footer renders correctly 1`] = `
|
|||
data-testid="gridContainer"
|
||||
>
|
||||
<a
|
||||
href="https://www.surveymonkey.com/r/cejst-survey"
|
||||
href="https://www.surveymonkey.com/r/P3LWTSB"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
|
@ -230,7 +220,7 @@ exports[`J40Footer renders correctly 1`] = `
|
|||
data-testid="button"
|
||||
type="button"
|
||||
>
|
||||
Help improve the site & data
|
||||
Help improve the tool
|
||||
<img
|
||||
alt="launch icon"
|
||||
src="test-file-stub"
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
|
||||
// Set nav links color to primary color (1b1b1b)
|
||||
.usa-nav__primary > .usa-nav__primary-item > a {
|
||||
@include u-text("gray-90");
|
||||
}
|
||||
|
||||
.logoNavRow {
|
||||
@include u-margin-top(4);
|
||||
|
@ -18,22 +14,8 @@
|
|||
@include u-display("flex");
|
||||
@include u-flex-direction("column");
|
||||
@include typeset("sans", 8, 3);
|
||||
}
|
||||
|
||||
.title2BetaPill {
|
||||
@include u-display("flex");
|
||||
}
|
||||
|
||||
.betaPill {
|
||||
@include u-display("inline-block");
|
||||
@include u-bg("yellow-20v");
|
||||
@include u-radius(1);
|
||||
@include u-padding-left(2);
|
||||
@include u-padding-right(2);
|
||||
@include u-padding-top('05');
|
||||
@include u-margin-left(1);
|
||||
@include u-font("body", "2xs");
|
||||
@include u-text('bold')
|
||||
max-width: 270px;
|
||||
min-width: 218px;
|
||||
}
|
||||
|
||||
.navLinks {
|
||||
|
|
|
@ -6,7 +6,7 @@ import J40Header from './J40Header';
|
|||
describe('rendering of the J40Header', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<J40Header />
|
||||
<J40Header location={location}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, {useState} from 'react';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Link, useIntl} from 'gatsby-plugin-intl';
|
||||
import {
|
||||
Alert,
|
||||
Header,
|
||||
NavMenuButton,
|
||||
PrimaryNav,
|
||||
|
@ -11,14 +12,19 @@ import {
|
|||
import BetaBanner from '../BetaBanner';
|
||||
import J40MainGridContainer from '../J40MainGridContainer';
|
||||
import GovernmentBanner from '../GovernmentBanner';
|
||||
import Language from '../Language';
|
||||
// import Language from '../Language';
|
||||
import {useWindowSize} from 'react-use';
|
||||
|
||||
// @ts-ignore
|
||||
import siteLogo from '../../images/j40-logo-v2.png';
|
||||
import * as styles from './J40Header.module.scss';
|
||||
import * as COMMON_COPY from '../../data/copy/common';
|
||||
import {PAGES_ENDPOINTS} from '../../data/constants';
|
||||
import {PAGES_ENDPOINTS, USWDS_BREAKPOINTS} from '../../data/constants';
|
||||
|
||||
|
||||
interface IJ40Header {
|
||||
location: Location
|
||||
}
|
||||
|
||||
/**
|
||||
* The J40Header component will control how the header looks for both mobile and desktop
|
||||
|
@ -28,37 +34,74 @@ import {PAGES_ENDPOINTS} from '../../data/constants';
|
|||
* 2. Logo and Nav Links Row
|
||||
* 3. Any Alerts
|
||||
*
|
||||
* @param {Location} location
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
const J40Header = () => {
|
||||
const J40Header = ({location}:IJ40Header) => {
|
||||
const intl = useIntl();
|
||||
const {width} = useWindowSize();
|
||||
|
||||
// grab last segment of location pathname
|
||||
const [lastSegmentLocation] = location.pathname.split('/').slice(-1);
|
||||
|
||||
// Logo text
|
||||
const logoLine1 = intl.formatMessage(COMMON_COPY.HEADER.TITLE_LINE_1);
|
||||
const logoLine2 = intl.formatMessage(COMMON_COPY.HEADER.TITLE_LINE_2);
|
||||
|
||||
/**
|
||||
* State variable to control the toggling of mobile menu button
|
||||
*/
|
||||
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
||||
const toggleMobileNav = (): void =>
|
||||
const toggleMobileNav = (): void => {
|
||||
setMobileNavOpen((prevOpen) => !prevOpen);
|
||||
};
|
||||
|
||||
/**
|
||||
* State variable to hold the open/close state of each nav dropdown. This will allow for two
|
||||
* dropdown that are being used, each corresponding to an index in the state array:
|
||||
*
|
||||
* index 0 = Data & Methodology dropdown (being used)
|
||||
* index 1 = About dropdown (removed for now)
|
||||
* index 0 = Data & Methodology dropdown
|
||||
* index 1 = About dropdown
|
||||
*/
|
||||
const [isOpen, setIsOpen] = useState([false, false]);
|
||||
|
||||
/**
|
||||
* When transitioning between anything larger than desktop and anything less than desktop the nav menu
|
||||
* changes from the usual row of nav links (dektop) to the MENU button(mobile). On desktop all nav drop
|
||||
* dropdowns should be closed, while on mobile all nav links should be open.
|
||||
*
|
||||
* The useWindowSize provides the device width and the useEffect allows the side effect (opening/closing
|
||||
* nav links) to occur anytime the device width changes.
|
||||
*/
|
||||
const {width} = useWindowSize();
|
||||
useEffect( () => {
|
||||
if (width < USWDS_BREAKPOINTS.DESKTOP) {
|
||||
setIsOpen([true, true]);
|
||||
} else {
|
||||
setIsOpen([false, false]);
|
||||
}
|
||||
}, [width]);
|
||||
|
||||
/**
|
||||
* This toggle function will handle both navigation toggle links (Meth and About).
|
||||
*
|
||||
* @param {number} index
|
||||
*/
|
||||
const [isOpen, setIsOpen] = useState([true]);
|
||||
const onToggle = (index: number): void => {
|
||||
// The setIsOpen is used to toggle the currently selected nav link
|
||||
setIsOpen((prevIsOpen) => {
|
||||
const newIsOpen = [true];
|
||||
const newIsOpen = [...isOpen];
|
||||
newIsOpen[index] = !prevIsOpen[index];
|
||||
return newIsOpen;
|
||||
});
|
||||
|
||||
/**
|
||||
* When on desktop only, the dropdown nav links (Meth and About) should close if any of the other ones
|
||||
* are still open. This next set of logic handles that.
|
||||
*/
|
||||
if (index === 0 && isOpen[1] === true && width > USWDS_BREAKPOINTS.DESKTOP) {
|
||||
setIsOpen([isOpen[0], false]);
|
||||
} else if (index === 1 && isOpen[0] === true && width > USWDS_BREAKPOINTS.DESKTOP) {
|
||||
setIsOpen([false, isOpen[1]]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -80,62 +123,20 @@ const J40Header = () => {
|
|||
data-cy={'nav-link-downloads'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.DOWNLOADS)}
|
||||
</Link>,
|
||||
// <Link
|
||||
// to={PAGES_ENDPOINTS.TSD}
|
||||
// key={'tsd'}
|
||||
// activeClassName="usa-current"
|
||||
// data-cy={'nav-link-technical-support-docs'}>
|
||||
// {intl.formatMessage(COMMON_COPY.HEADER.TSD)}
|
||||
// </Link>,
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.PREVIOUS_VERSIONS}
|
||||
key={'previous-versions'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-previous-versions'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.PREVIOUS_VERSIONS)}
|
||||
</Link>,
|
||||
];
|
||||
|
||||
/**
|
||||
* In the future, we may want to add sub-pages to the About page. This array will
|
||||
* define the sub-pages for the About page.
|
||||
* On mobile, the About page should have 3 sub-nav links. This defines
|
||||
* the array that will hold these links
|
||||
*/
|
||||
// const aboutSubNavLinks = [
|
||||
// <Link
|
||||
// to={PAGES_ENDPOINTS.ABOUT}
|
||||
// key={'about'}
|
||||
// activeClassName="usa-current"
|
||||
// data-cy={'nav-link-about'}>
|
||||
// {intl.formatMessage(COMMON_COPY.HEADER.ABOUT)}
|
||||
// </Link>,
|
||||
// <Link
|
||||
// to={PAGES_ENDPOINTS.FAQS}
|
||||
// key={'faqs'}
|
||||
// activeClassName="usa-current"
|
||||
// data-cy={'nav-link-faqs'}>
|
||||
// {intl.formatMessage(COMMON_COPY.HEADER.FAQs)}
|
||||
// </Link>,
|
||||
// <Link
|
||||
// to={PAGES_ENDPOINTS.PUBLIC_ENG}
|
||||
// key={'publicEng'}
|
||||
// activeClassName="usa-current"
|
||||
// data-cy={'nav-link-public-engagement'}>
|
||||
// {intl.formatMessage(COMMON_COPY.HEADER.PUBLIC_ENG)}
|
||||
// </Link>,
|
||||
// ];
|
||||
|
||||
|
||||
/**
|
||||
* This is the array that holds the navigation links and eventually is the one
|
||||
* that is passed to the render function. It only defines Explore, About and
|
||||
* Contact.
|
||||
*
|
||||
* The Methodology & Data link is passed in depending on screen size.
|
||||
*
|
||||
* For mobile: the Methodology & Data link should have sub-pages
|
||||
* For desktop: the Methodology & Data link should NOT have sub-pages
|
||||
*/
|
||||
const navLinks = [
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.EXPLORE}
|
||||
key={'explore-map'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-explore-the-map'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.EXPLORE)}
|
||||
</Link>,
|
||||
const aboutPageSubNavLinks = [
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.ABOUT}
|
||||
key={'about'}
|
||||
|
@ -144,21 +145,33 @@ const J40Header = () => {
|
|||
{intl.formatMessage(COMMON_COPY.HEADER.ABOUT)}
|
||||
</Link>,
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.CONTACT}
|
||||
key={'contact'}
|
||||
to={PAGES_ENDPOINTS.PUBLIC_ENG}
|
||||
key={'publicEng'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-contact'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.CONTACT)}
|
||||
data-cy={'nav-link-public-engagement'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.PUBLIC_ENG)}
|
||||
</Link>,
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.FAQS}
|
||||
key={'faqs'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-faqs'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.FAQS)}
|
||||
</Link>,
|
||||
<div key={'language'}>
|
||||
<Language isDesktop={false}/>
|
||||
</div>,
|
||||
];
|
||||
|
||||
// For mobile: the Methodology & Data link should have sub-pages
|
||||
const MethPageNavWithSubPages = () =>
|
||||
// Methodology & Data Nav component
|
||||
const MethNav = () =>
|
||||
<>
|
||||
{/* Add a className of usa-current anytime this component renders when the location of the app is on
|
||||
the Methodology page or the downloads page. This will style the nav link with a bottom border */}
|
||||
<NavDropDownButton
|
||||
className={
|
||||
lastSegmentLocation === PAGES_ENDPOINTS.METHODOLOGY.slice(1) ||
|
||||
lastSegmentLocation === PAGES_ENDPOINTS.DOWNLOADS.slice(1) ?
|
||||
'usa-current' :
|
||||
''
|
||||
}
|
||||
key="methDropDown"
|
||||
label={intl.formatMessage(COMMON_COPY.HEADER.METHODOLOGY)}
|
||||
menuId="methMenu"
|
||||
|
@ -176,18 +189,59 @@ const J40Header = () => {
|
|||
</Menu>
|
||||
</>;
|
||||
|
||||
// For desktop: the Methodology & Data link should NOT have sub-pages
|
||||
const MethPageNav = () =>
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.METHODOLOGY}
|
||||
key={'methodology'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-methodology'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.METHODOLOGY)}
|
||||
</Link>;
|
||||
// About Nav component
|
||||
const AboutNav = () =>
|
||||
<>
|
||||
{/* Add a className of usa-current anytime this component renders when the location of the app is on
|
||||
the About, FAQS or Public Eng page. This will style the nav link with a bottom border */}
|
||||
<NavDropDownButton
|
||||
className={
|
||||
lastSegmentLocation === PAGES_ENDPOINTS.ABOUT.slice(1) ||
|
||||
lastSegmentLocation === PAGES_ENDPOINTS.FAQS.slice(1) ||
|
||||
lastSegmentLocation === PAGES_ENDPOINTS.PUBLIC_ENG.slice(1) ?
|
||||
'usa-current' :
|
||||
''
|
||||
}
|
||||
key="aboutDropDown"
|
||||
label={intl.formatMessage(COMMON_COPY.HEADER.ABOUT)}
|
||||
menuId="aboutMenu"
|
||||
isOpen={isOpen[1]}
|
||||
onToggle={(): void => onToggle(1)}
|
||||
data-cy={'nav-dropdown-about'}
|
||||
>
|
||||
</NavDropDownButton>
|
||||
<Menu
|
||||
id='aboutMenu'
|
||||
type='subnav'
|
||||
items={aboutPageSubNavLinks}
|
||||
isOpen={isOpen[1]}
|
||||
>
|
||||
</Menu>
|
||||
</>;
|
||||
|
||||
// Modify navLinks to choose the appropriate Methodology & Data nav link depending on screen size
|
||||
navLinks.splice(1, 0, width > 1024 ? <MethPageNav/> : <MethPageNavWithSubPages/>);
|
||||
// Navigation links for app
|
||||
const navLinks = [
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.EXPLORE}
|
||||
key={'explore-map'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-explore-the-map'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.EXPLORE)}
|
||||
</Link>,
|
||||
<MethNav key="methDropDown"/>,
|
||||
<AboutNav key="aboutDropDown"/>,
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.CONTACT}
|
||||
key={'contact'}
|
||||
activeClassName="usa-current"
|
||||
data-cy={'nav-link-contact'}>
|
||||
{intl.formatMessage(COMMON_COPY.HEADER.CONTACT)}
|
||||
</Link>,
|
||||
// Temporarily removing language link until translation is completed
|
||||
// <div key={'language'}>
|
||||
// <Language isDesktop={false}/>
|
||||
// </div>,
|
||||
];
|
||||
|
||||
return (
|
||||
<Header basic={true} role={'banner'}>
|
||||
|
@ -203,18 +257,27 @@ const J40Header = () => {
|
|||
|
||||
{/* Logo */}
|
||||
<Grid col={1}>
|
||||
<img className={styles.logo} src={siteLogo} alt={`${logoLine1} ${logoLine2}`} />
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.EXPLORE}
|
||||
key={'explore-map'}
|
||||
data-cy={'nav-link-explore-the-map'}
|
||||
>
|
||||
<img className={styles.logo} src={siteLogo} alt={`${logoLine1}`} />
|
||||
</Link>
|
||||
</Grid>
|
||||
|
||||
{/* Logo Title */}
|
||||
<Grid col={6}>
|
||||
<div className={styles.logoTitle}>
|
||||
<div>{logoLine1}</div>
|
||||
<div className={styles.title2BetaPill}>
|
||||
<div> {logoLine2} </div>
|
||||
<div className={styles.betaPill}>BETA</div>
|
||||
<Link
|
||||
to={PAGES_ENDPOINTS.EXPLORE}
|
||||
key={'explore-map'}
|
||||
className="remove-link-style"
|
||||
data-cy={'nav-link-explore-the-map'}
|
||||
>
|
||||
<div className={styles.logoTitle}>
|
||||
{logoLine1}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</Grid>
|
||||
|
||||
{/* Nav links */}
|
||||
|
@ -237,22 +300,24 @@ const J40Header = () => {
|
|||
</J40MainGridContainer>
|
||||
|
||||
{/* Alert */}
|
||||
{/* {<J40MainGridContainer>
|
||||
<Alert
|
||||
{<J40MainGridContainer>
|
||||
{/* <Alert
|
||||
className={styles.alert}
|
||||
type="info"
|
||||
heading={intl.formatMessage(COMMON_COPY.ALERTS.ALERT_2_TITLE.TITLE)}>
|
||||
heading={intl.formatMessage(COMMON_COPY.ALERTS.ALERT_2_TITLE.TITLE)}
|
||||
headingLevel={'h1'}>
|
||||
{COMMON_COPY.ALERTS.ALERT_2_DESCRIPTION}
|
||||
</Alert>
|
||||
</Alert> */}
|
||||
|
||||
<Alert
|
||||
className={styles.alert}
|
||||
type="info"
|
||||
heading={intl.formatMessage(COMMON_COPY.ALERTS.ALERT_1_TITLE.TITLE)}>
|
||||
heading={intl.formatMessage(COMMON_COPY.ALERTS.ALERT_1_TITLE.TITLE)}
|
||||
headingLevel={'h1'}>
|
||||
{COMMON_COPY.ALERTS.ALERT_1_DESCRIPTION}
|
||||
</Alert>
|
||||
</J40MainGridContainer>
|
||||
} */}
|
||||
}
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -140,36 +140,14 @@ exports[`rendering of the J40Header checks if component renders 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div>
|
||||
<img
|
||||
alt="language icon for selecting language"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
English
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
Español
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div />
|
||||
<div>
|
||||
<span>
|
||||
This is a beta site.
|
||||
</span>
|
||||
<span>
|
||||
It is an early, in-progress version of the tool with limited datasets that will
|
||||
be regularly updated.
|
||||
</span>
|
||||
</div>
|
||||
<strong>
|
||||
This tool has been updated.
|
||||
</strong>
|
||||
The 1.0 version of the tool was released on Nov 22, 2022.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -184,28 +162,29 @@ exports[`rendering of the J40Header checks if component renders 1`] = `
|
|||
class="grid-col-1"
|
||||
data-testid="grid"
|
||||
>
|
||||
<img
|
||||
alt="Climate and Economic Justice Screening Tool"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<a
|
||||
data-cy="nav-link-explore-the-map"
|
||||
href="/en/"
|
||||
>
|
||||
<img
|
||||
alt="Climate and Economic Justice Screening Tool"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="grid-col-6"
|
||||
data-testid="grid"
|
||||
>
|
||||
<div>
|
||||
<a
|
||||
class="remove-link-style"
|
||||
data-cy="nav-link-explore-the-map"
|
||||
href="/en/"
|
||||
>
|
||||
<div>
|
||||
Climate and Economic Justice
|
||||
Climate and Economic Justice Screening Tool
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
Screening Tool
|
||||
</div>
|
||||
<div>
|
||||
BETA
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="grid-col-fill"
|
||||
|
@ -249,7 +228,7 @@ exports[`rendering of the J40Header checks if component renders 1`] = `
|
|||
>
|
||||
<button
|
||||
aria-controls="methMenu"
|
||||
aria-expanded="true"
|
||||
aria-expanded="false"
|
||||
class="usa-accordion__button usa-nav__link"
|
||||
data-cy="nav-dropdown-methodology"
|
||||
data-testid="navDropDownButton"
|
||||
|
@ -261,6 +240,7 @@ exports[`rendering of the J40Header checks if component renders 1`] = `
|
|||
</button>
|
||||
<ul
|
||||
class="usa-nav__submenu"
|
||||
hidden=""
|
||||
id="methMenu"
|
||||
>
|
||||
<li
|
||||
|
@ -283,17 +263,69 @@ exports[`rendering of the J40Header checks if component renders 1`] = `
|
|||
Downloads
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="usa-nav__submenu-item"
|
||||
>
|
||||
<a
|
||||
data-cy="nav-link-previous-versions"
|
||||
href="/en/previous-versions"
|
||||
>
|
||||
Previous versions
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li
|
||||
class="usa-nav__primary-item"
|
||||
>
|
||||
<a
|
||||
data-cy="nav-link-about"
|
||||
href="/en/about"
|
||||
<button
|
||||
aria-controls="aboutMenu"
|
||||
aria-expanded="false"
|
||||
class="usa-accordion__button usa-nav__link"
|
||||
data-cy="nav-dropdown-about"
|
||||
data-testid="navDropDownButton"
|
||||
type="button"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
<span>
|
||||
About
|
||||
</span>
|
||||
</button>
|
||||
<ul
|
||||
class="usa-nav__submenu"
|
||||
hidden=""
|
||||
id="aboutMenu"
|
||||
>
|
||||
<li
|
||||
class="usa-nav__submenu-item"
|
||||
>
|
||||
<a
|
||||
data-cy="nav-link-about"
|
||||
href="/en/about"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="usa-nav__submenu-item"
|
||||
>
|
||||
<a
|
||||
data-cy="nav-link-public-engagement"
|
||||
href="/en/public-engagement"
|
||||
>
|
||||
Engagement calendar
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="usa-nav__submenu-item"
|
||||
>
|
||||
<a
|
||||
data-cy="nav-link-faqs"
|
||||
href="/en/frequently-asked-questions"
|
||||
>
|
||||
Frequently asked questions
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li
|
||||
class="usa-nav__primary-item"
|
||||
|
@ -305,33 +337,35 @@ exports[`rendering of the J40Header checks if component renders 1`] = `
|
|||
Contact
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
class="usa-nav__primary-item"
|
||||
>
|
||||
<div>
|
||||
<div>
|
||||
<img
|
||||
alt="language icon for selecting language"
|
||||
src="test-file-stub"
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
English
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
Español
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid-container-desktop-lg"
|
||||
data-testid="gridContainer"
|
||||
>
|
||||
<div
|
||||
class="usa-alert usa-alert--info"
|
||||
data-testid="alert"
|
||||
>
|
||||
<div
|
||||
class="usa-alert__body"
|
||||
>
|
||||
<h1
|
||||
class="usa-alert__heading"
|
||||
>
|
||||
Version 1.0 of the tool is now available
|
||||
</h1>
|
||||
<p
|
||||
class="usa-alert__text"
|
||||
>
|
||||
The Council on Environmental Quality (CEQ) made the version 1.0 of the tool available on 11/22/2022. For more information about the improvements to the tool, CEQ’s press release will be coming soon.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
|
|
@ -1,30 +1,76 @@
|
|||
@use '../styles/design-system.scss' as *;
|
||||
@import "./utils.scss";
|
||||
|
||||
.j40Popup {
|
||||
width: 375px;
|
||||
}
|
||||
|
||||
.navigationControl {
|
||||
left: .75em;
|
||||
top: units(15);
|
||||
// width: 2.5em;
|
||||
}
|
||||
.j40Map {
|
||||
// width < 1024
|
||||
@include at-media-max("desktop") {
|
||||
height: 55vh;
|
||||
}
|
||||
|
||||
.fullscreenControl {
|
||||
right: 1.25em;
|
||||
top: 2.5em;
|
||||
}
|
||||
.mapHeaderRow{
|
||||
@include u-display("flex");
|
||||
@include u-padding-left(1.5);
|
||||
|
||||
@include at-media-max("mobile-lg") {
|
||||
flex-direction: column;
|
||||
|
||||
@include u-padding-right(1.5);
|
||||
|
||||
.geolocateBox {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.geolocateBox > div {
|
||||
right: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.geolocateBox {
|
||||
margin-top: 6px;
|
||||
@include u-margin-left(1);
|
||||
|
||||
.geolocateMessage {
|
||||
visibility: visible;
|
||||
background-color: white;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.geolocateMessageHide {
|
||||
visibility: hidden;
|
||||
min-width: fit-content;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.navigationControl {
|
||||
left: .75em;
|
||||
top: units(15);
|
||||
}
|
||||
|
||||
//These classes are behind feature flags:
|
||||
.fullscreenControl {
|
||||
right: 1.25em;
|
||||
top: 2.5em;
|
||||
}
|
||||
.j40Popup {
|
||||
width: 375px;
|
||||
}
|
||||
|
||||
.geolocateControl {
|
||||
right: 1.25em;
|
||||
top: 5em;
|
||||
}
|
||||
|
||||
.mapInfoPanel {
|
||||
border: 1px solid $sidePanelBorderColor;
|
||||
overflow-y: auto;
|
||||
height: 90vh;
|
||||
|
||||
@include at-media-max("mobile-lg") {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// This will control the height of the map when the device
|
||||
|
|
25
client/src/components/J40Map.module.scss.d.ts
vendored
25
client/src/components/J40Map.module.scss.d.ts
vendored
|
@ -1,14 +1,23 @@
|
|||
declare namespace J40MapModuleScssNamespace {
|
||||
export interface IJ40MapModuleScss {
|
||||
j40Popup: string;
|
||||
territoryFocusButton: string;
|
||||
territoryFocusContainer: string;
|
||||
navigationControl: string;
|
||||
fullscreenControl: string;
|
||||
geolocateControl: string;
|
||||
detailView: string;
|
||||
mapInfoPanel: string;
|
||||
// main J40 map style
|
||||
j40Map: string;
|
||||
|
||||
// map header row
|
||||
mapHeaderRow: string;
|
||||
geolocateBox: string;
|
||||
geolocateMessage: string;
|
||||
geolocateMessageHide: string;
|
||||
geolocateIcon: string;
|
||||
|
||||
// nav control
|
||||
navigationControl: string;
|
||||
|
||||
// feature flags
|
||||
fullscreenControl: string;
|
||||
j40Popup: string;
|
||||
|
||||
mapInfoPanel: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable valid-jsdoc */
|
||||
/* eslint-disable no-unused-vars */
|
||||
// External Libs:
|
||||
import React, {useRef, useState, useMemo} from 'react';
|
||||
import React, {useRef, useState} from 'react';
|
||||
import {Map, MapboxGeoJSONFeature, LngLatBoundsLike} from 'maplibre-gl';
|
||||
import ReactMapGL, {
|
||||
MapEvent,
|
||||
|
@ -12,12 +12,13 @@ import ReactMapGL, {
|
|||
Popup,
|
||||
FlyToInterpolator,
|
||||
FullscreenControl,
|
||||
MapRef, Source, Layer} from 'react-map-gl';
|
||||
MapRef} from 'react-map-gl';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import bbox from '@turf/bbox';
|
||||
import * as d3 from 'd3-ease';
|
||||
import {isMobile} from 'react-device-detect';
|
||||
import {Grid} from '@trussworks/react-uswds';
|
||||
import {useWindowSize} from 'react-use';
|
||||
import {useWindowSize, useLocalStorage} from 'react-use';
|
||||
|
||||
// Contexts:
|
||||
import {useFlags} from '../contexts/FlagContext';
|
||||
|
@ -26,6 +27,8 @@ import {useFlags} from '../contexts/FlagContext';
|
|||
import AreaDetail from './AreaDetail';
|
||||
import MapInfoPanel from './mapInfoPanel';
|
||||
import MapSearch from './MapSearch';
|
||||
import MapTractLayers from './MapTractLayers/MapTractLayers';
|
||||
// import MapTribalLayer from './MapTribalLayers/MapTribalLayers';
|
||||
import TerritoryFocusControl from './territoryFocusControl';
|
||||
import {getOSBaseMap} from '../data/getOSBaseMap';
|
||||
|
||||
|
@ -33,8 +36,7 @@ import {getOSBaseMap} from '../data/getOSBaseMap';
|
|||
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
import * as constants from '../data/constants';
|
||||
import * as styles from './J40Map.module.scss';
|
||||
import * as COMMON_COPY from '../data/copy/common';
|
||||
|
||||
import * as EXPLORE_COPY from '../data/copy/explore';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
@ -55,50 +57,6 @@ export interface IDetailViewInterface {
|
|||
properties: constants.J40Properties,
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will determine the URL for the map tiles. It will read in a string that will designate either
|
||||
* high or low tiles. It will allow to overide the URL to the pipeline staging tile URL via feature flag.
|
||||
* Lastly, it allows to set the tiles to be local or via the CDN as well.
|
||||
*
|
||||
* @param {string} tilesetName
|
||||
* @returns {string}
|
||||
*/
|
||||
export const featureURLForTilesetName = (tilesetName: string): string => {
|
||||
const flags = useFlags();
|
||||
|
||||
const pipelineStagingBaseURL = `https://justice40-data.s3.amazonaws.com/data-pipeline-staging`;
|
||||
const XYZ_SUFFIX = '{z}/{x}/{y}.pbf';
|
||||
|
||||
if ('stage_hash' in flags) {
|
||||
// Check if the stage_hash is valid
|
||||
const regex = /^[0-9]{4}\/[a-f0-9]{40}$/;
|
||||
if (!regex.test(flags['stage_hash'])) {
|
||||
console.error(COMMON_COPY.CONSOLE_ERROR.STAGE_URL);
|
||||
}
|
||||
|
||||
return `${pipelineStagingBaseURL}/${flags['stage_hash']}/data/score/tiles/${tilesetName}/${XYZ_SUFFIX}`;
|
||||
} else {
|
||||
// The feature tile base URL and path can either point locally or the CDN.
|
||||
// This is selected based on the DATA_SOURCE env variable.
|
||||
const featureTileBaseURL = process.env.DATA_SOURCE === 'local' ?
|
||||
process.env.GATSBY_LOCAL_TILES_BASE_URL :
|
||||
process.env.GATSBY_CDN_TILES_BASE_URL;
|
||||
|
||||
const featureTilePath = process.env.DATA_SOURCE === 'local' ?
|
||||
process.env.GATSBY_DATA_PIPELINE_SCORE_PATH_LOCAL :
|
||||
process.env.GATSBY_DATA_PIPELINE_SCORE_PATH;
|
||||
|
||||
return [
|
||||
featureTileBaseURL,
|
||||
featureTilePath,
|
||||
process.env.GATSBY_MAP_TILES_PATH,
|
||||
tilesetName,
|
||||
XYZ_SUFFIX,
|
||||
].join('/');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const J40Map = ({location}: IJ40Interface) => {
|
||||
/**
|
||||
* Initializes the zoom, and the map's center point (lat, lng) via the URL hash #{z}/{lat}/{long}
|
||||
|
@ -129,11 +87,23 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
const [isMobileMapState, setIsMobileMapState] = useState<boolean>(false);
|
||||
const {width: windowWidth} = useWindowSize();
|
||||
|
||||
/**
|
||||
* Store the geolocation lock state in local storage. The Geolocation component from MapBox does not
|
||||
* expose (API) various geolocation lock/unlock states in the version we are using. This makes it
|
||||
* challenging to change the UI state to match the Geolocation state. A work around is to store the
|
||||
* geolocation "locked" state in local storage. The local storage state will then be used to show the
|
||||
* "Finding location" message. The local storage will be removed everytime the map is reloaded.
|
||||
*
|
||||
* The "Finding location" message only applies for desktop layouts.
|
||||
*/
|
||||
// eslint-disable-next-line max-len
|
||||
const [isGeolocateLocked, setIsGeolocateLocked, removeGeolocateLock] = useLocalStorage('is-geolocate-locked', false, {raw: true});
|
||||
|
||||
const mapRef = useRef<MapRef>(null);
|
||||
const flags = useFlags();
|
||||
const intl = useIntl();
|
||||
|
||||
const selectedFeatureId = (selectedFeature && selectedFeature.id) || '';
|
||||
const filter = useMemo(() => ['in', constants.GEOID_PROPERTY, selectedFeatureId], [selectedFeature]);
|
||||
|
||||
const zoomLatLngHash = mapRef.current?.getMap()._hash._getCurrentHash();
|
||||
|
||||
|
@ -199,6 +169,7 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
}
|
||||
} else {
|
||||
// This else clause will fire when the ID is null or empty. This is the case where the map is clicked
|
||||
|
||||
// @ts-ignore
|
||||
const feature = event.features && event.features[0];
|
||||
|
||||
|
@ -206,6 +177,7 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
// Get the current selected feature's bounding box:
|
||||
const [minLng, minLat, maxLng, maxLat] = bbox(feature);
|
||||
|
||||
|
||||
// Set the selectedFeature ID
|
||||
if (feature.id !== selectedFeatureId) {
|
||||
setSelectedFeature(feature);
|
||||
|
@ -213,7 +185,8 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
setSelectedFeature(undefined);
|
||||
}
|
||||
|
||||
// Go to the newly selected feature
|
||||
|
||||
// Go to the newly selected feature (as long as it's not an Alaska Point)
|
||||
goToPlace([
|
||||
[minLng, minLat],
|
||||
[maxLng, maxLat],
|
||||
|
@ -260,6 +233,9 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
window.underlyingMap = mapRef.current.getMap();
|
||||
}
|
||||
|
||||
// When map loads remove the geolocate lock boolean in local storage
|
||||
removeGeolocateLock();
|
||||
|
||||
if (isMobile) setIsMobileMapState(true);
|
||||
};
|
||||
|
||||
|
@ -275,7 +251,7 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
* @param {LngLatBoundsLike} bounds
|
||||
* @param {boolean} isTerritory
|
||||
*/
|
||||
const goToPlace = (bounds: LngLatBoundsLike, isTerritory = false ) => {
|
||||
const goToPlace = (bounds: LngLatBoundsLike, isTerritory = false) => {
|
||||
const newViewPort = new WebMercatorViewport({height: viewport.height!, width: viewport.width!});
|
||||
const {longitude, latitude, zoom} = newViewPort.fitBounds(
|
||||
bounds as [[number, number], [number, number]], {
|
||||
|
@ -318,23 +294,30 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
|
||||
const onGeolocate = () => {
|
||||
setGeolocationInProgress(false);
|
||||
|
||||
// set local storage that location was locked on this app at some point
|
||||
setIsGeolocateLocked(true);
|
||||
};
|
||||
|
||||
const onClickGeolocate = () => {
|
||||
setGeolocationInProgress(true);
|
||||
};
|
||||
|
||||
const mapBoxBaseLayer = 'tl' in flags ? `mapbox://styles/justice40/cl2qimpi2000014qeb1egpox8` : `mapbox://styles/justice40/cl4gb253h000014s6r4xwjm10`;
|
||||
const mapBoxBaseLayer = {
|
||||
customColorsWithUpdatedTribal: `mapbox://styles/justice40/cl9g30qh7000p15l9cp1ftw16`,
|
||||
streetsWithUpdatedTribal: `mapbox://styles/justice40/cl98rlidr002c14obpsvz6zzs`,
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid desktop={{col: 9}} className={styles.j40Map}>
|
||||
|
||||
{/**
|
||||
* This will render the MapSearch component
|
||||
*
|
||||
* Note:
|
||||
* The MapSearch component is no longer wrapped in a div in order to allow this feature
|
||||
* The MapSearch component is no longer used in this location. It has been moved inside the
|
||||
* <ReactMapGL> component itself.
|
||||
*
|
||||
* It was originally wrapped in a div in order to allow this feature
|
||||
* to be behind a feature flag. This was causing a bug for MapSearch to render
|
||||
* correctly in a production build. Leaving this comment here in case future flags are
|
||||
* needed in this component.
|
||||
|
@ -346,9 +329,9 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
* - npm run clean && npm run build && npm run serve
|
||||
*
|
||||
* to ensure the production build works and that MapSearch and the map (ReactMapGL) render correctly.
|
||||
*
|
||||
* Any component declarations outside the <ReactMapGL> component may be susceptible to this bug.
|
||||
*/}
|
||||
<MapSearch goToPlace={goToPlace}/>
|
||||
|
||||
|
||||
{/**
|
||||
* The ReactMapGL component's props are grouped by the API's documentation. The component also has
|
||||
|
@ -364,7 +347,8 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
// ****** Map state props: ******
|
||||
// http://visgl.github.io/react-map-gl/docs/api-reference/interactive-map#map-state
|
||||
{...viewport}
|
||||
mapStyle={process.env.MAPBOX_STYLES_READ_TOKEN ? mapBoxBaseLayer : getOSBaseMap()}
|
||||
mapStyle={process.env.MAPBOX_STYLES_READ_TOKEN ?
|
||||
mapBoxBaseLayer.customColorsWithUpdatedTribal : getOSBaseMap()}
|
||||
width="100%"
|
||||
// Ajusting this height with a conditional statement will not render the map on staging.
|
||||
// The reason for this issue is unknown. Consider styling the parent container via SASS.
|
||||
|
@ -378,7 +362,13 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
minZoom={constants.GLOBAL_MIN_ZOOM}
|
||||
dragRotate={false}
|
||||
touchRotate={false}
|
||||
interactiveLayerIds={[constants.HIGH_ZOOM_LAYER_ID, constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID]}
|
||||
// eslint-disable-next-line max-len
|
||||
interactiveLayerIds={
|
||||
[
|
||||
constants.HIGH_ZOOM_LAYER_ID,
|
||||
constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
// ****** Callback props: ******
|
||||
|
@ -388,119 +378,54 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
onLoad={onLoad}
|
||||
onTransitionStart={onTransitionStart}
|
||||
onTransitionEnd={onTransitionEnd}
|
||||
|
||||
ref={mapRef}
|
||||
data-cy={'reactMapGL'}
|
||||
>
|
||||
{/**
|
||||
* The low zoom source
|
||||
*/}
|
||||
<Source
|
||||
id={constants.LOW_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[featureURLForTilesetName('low')]}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_LOW}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_LOW}
|
||||
>
|
||||
|
||||
{/* Low zoom layer - prioritized features only */}
|
||||
<Layer
|
||||
id={constants.LOW_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['>', constants.SCORE_PROPERTY_LOW, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.LOW_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY}}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_LOW}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_LOW}
|
||||
/>
|
||||
</Source>
|
||||
<MapTractLayers
|
||||
selectedFeature={selectedFeature}
|
||||
selectedFeatureId={selectedFeatureId}
|
||||
/>
|
||||
|
||||
{/**
|
||||
* The high zoom source
|
||||
*/}
|
||||
<Source
|
||||
id={constants.HIGH_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[featureURLForTilesetName('high')]}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_HIGH}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
>
|
||||
{/* This is the first overlayed row on the map: Search and Geolocation */}
|
||||
<div className={styles.mapHeaderRow}>
|
||||
<MapSearch goToPlace={goToPlace}/>
|
||||
|
||||
{/* High zoom layer - non-prioritized features only */}
|
||||
<Layer
|
||||
id={constants.HIGH_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['<', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-opacity': constants.NON_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
{/* Geolocate Icon */}
|
||||
<div className={styles.geolocateBox}>
|
||||
{
|
||||
windowWidth > constants.USWDS_BREAKPOINTS.MOBILE_LG - 1 &&
|
||||
<div className={
|
||||
(geolocationInProgress && !isGeolocateLocked) ?
|
||||
styles.geolocateMessage :
|
||||
styles.geolocateMessageHide
|
||||
}>
|
||||
{intl.formatMessage(EXPLORE_COPY.MAP.GEOLOC_MSG_LOCATING)}
|
||||
</div>
|
||||
}
|
||||
<GeolocateControl
|
||||
positionOptions={{enableHighAccuracy: true}}
|
||||
onGeolocate={onGeolocate}
|
||||
onClick={onClickGeolocate}
|
||||
trackUserLocation={windowWidth < constants.USWDS_BREAKPOINTS.MOBILE_LG}
|
||||
showUserHeading={windowWidth < constants.USWDS_BREAKPOINTS.MOBILE_LG}
|
||||
disabledLabel={intl.formatMessage(EXPLORE_COPY.MAP.GEOLOC_MSG_DISABLED)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* High zoom layer - prioritized features only */}
|
||||
<Layer
|
||||
id={constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['>', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.HIGH_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* High zoom layer - controls the border between features */}
|
||||
<Layer
|
||||
id={constants.FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.FEATURE_BORDER_WIDTH,
|
||||
'line-opacity': constants.FEATURE_BORDER_OPACITY,
|
||||
}}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_FEATURE_BORDER}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_FEATURE_BORDER}
|
||||
/>
|
||||
|
||||
{/* High zoom layer - border styling around the selected feature */}
|
||||
<Layer
|
||||
id={constants.SELECTED_FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={filter} // This filter filters out all other features except the selected feature.
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.SELECTED_FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.SELECTED_FEATURE_BORDER_WIDTH,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
</Source>
|
||||
|
||||
{/* This will add the navigation controls of the zoom in and zoom out buttons */}
|
||||
{/* This is the second row overlayed on the map, it will add the navigation controls
|
||||
of the zoom in and zoom out buttons */}
|
||||
{ windowWidth > constants.USWDS_BREAKPOINTS.MOBILE_LG && <NavigationControl
|
||||
showCompass={false}
|
||||
className={styles.navigationControl}
|
||||
/> }
|
||||
|
||||
{/* This will show shortcut buttons to pan/zoom to US territories */}
|
||||
<TerritoryFocusControl onClick={onClick}/>
|
||||
|
||||
{/* This places Geolocation behind a feature flag */}
|
||||
{'gl' in flags ? <GeolocateControl
|
||||
className={styles.geolocateControl}
|
||||
positionOptions={{enableHighAccuracy: true}}
|
||||
onGeolocate={onGeolocate}
|
||||
// @ts-ignore
|
||||
onClick={onClickGeolocate}
|
||||
/> : ''}
|
||||
{geolocationInProgress ? <div>Geolocation in progress...</div> : ''}
|
||||
{/* This is the third row overlayed on the map, it will show shortcut buttons to
|
||||
pan/zoom to US territories */}
|
||||
{ windowWidth > constants.USWDS_BREAKPOINTS.MOBILE_LG &&
|
||||
<TerritoryFocusControl onClick={onClick}/> }
|
||||
|
||||
{/* Enable fullscreen pop-up behind a feature flag */}
|
||||
{('fs' in flags && detailViewData && !transitionInProgress) && (
|
||||
|
@ -514,7 +439,10 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
onClose={setDetailViewData}
|
||||
captureScroll={true}
|
||||
>
|
||||
<AreaDetail properties={detailViewData.properties} hash={zoomLatLngHash}/>
|
||||
<AreaDetail
|
||||
properties={detailViewData.properties}
|
||||
hash={zoomLatLngHash}
|
||||
/>
|
||||
</Popup>
|
||||
)}
|
||||
{'fs' in flags ? <FullscreenControl className={styles.fullscreenControl}/> :'' }
|
||||
|
|
|
@ -11,13 +11,11 @@
|
|||
.languageLink {
|
||||
@include u-display("inline-block");
|
||||
@include u-margin-left(1.5);
|
||||
|
||||
cursor: pointer;
|
||||
font-size: .8rem; // government banner text size not a token
|
||||
@include u-padding-top('2px');
|
||||
|
||||
&:hover {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ const Language = ({isDesktop}:ILanguageProps) => {
|
|||
languages.map((language: React.Key | null | undefined) => (
|
||||
<a
|
||||
href="#"
|
||||
className={styles.languageLink}
|
||||
className={styles.languageLink ? `usa-link ${styles.languageLink}` : `usa-link`}
|
||||
key={language}
|
||||
onClick={() => changeLocale(language)}
|
||||
>
|
||||
|
|
|
@ -10,11 +10,13 @@ exports[`rendering of the Language component on mobile checks if component rende
|
|||
src="test-file-stub"
|
||||
/>
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#"
|
||||
>
|
||||
English
|
||||
</a>
|
||||
<a
|
||||
class="usa-link"
|
||||
href="#"
|
||||
>
|
||||
Español
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
|
||||
.layerSelectorContainer {
|
||||
background-color: white;
|
||||
@include u-padding-left(1);
|
||||
@include u-padding-right(1);
|
||||
@include u-padding-top(1);
|
||||
@include u-padding-bottom(1);
|
||||
width: fit-content;
|
||||
z-index: 1;
|
||||
|
||||
// styles for mobile-lg (480px) and greater widths,
|
||||
@include at-media('mobile-lg') {
|
||||
@include u-margin-top(3);
|
||||
@include u-margin-right(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
12
client/src/components/LayerSelector/LayerSelector.module.scss.d.ts
vendored
Normal file
12
client/src/components/LayerSelector/LayerSelector.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
declare namespace LayerSelectorNamespace {
|
||||
export interface ILayerSelectorScss {
|
||||
layerSelectorContainer: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const LayerSelectorScssModule: LayerSelectorNamespace.ILayerSelectorScss & {
|
||||
/** WARNING: Only available when `css-loader` is used without `style-loader` or `mini-css-extract-plugin` */
|
||||
locals: LayerSelectorNamespace.ILayerSelectorScss;
|
||||
};
|
||||
|
||||
export = LayerSelectorScssModule;
|
24
client/src/components/LayerSelector/LayerSelector.test.tsx
Normal file
24
client/src/components/LayerSelector/LayerSelector.test.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../test/testHelpers';
|
||||
import LayerSelector from './LayerSelector';
|
||||
|
||||
describe('rendering of the LayerSelector', () => {
|
||||
it('checks if component renders census tracts selected', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<LayerSelector censusSelected={true} setCensusSelected={() => {}} setLayerToggled={() =>{}}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('checks if component renders tribal selected', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<LayerSelector censusSelected={false} setCensusSelected={() => {}} setLayerToggled={()=> {}}/>
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
74
client/src/components/LayerSelector/LayerSelector.tsx
Normal file
74
client/src/components/LayerSelector/LayerSelector.tsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
import React, {useEffect, useState, Dispatch} from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {Button, ButtonGroup} from '@trussworks/react-uswds';
|
||||
import {useWindowSize} from 'react-use';
|
||||
|
||||
|
||||
import * as styles from './LayerSelector.module.scss';
|
||||
import * as EXPLORE_COPY from '../../data/copy/explore';
|
||||
|
||||
interface ILayerSelector {
|
||||
censusSelected: boolean,
|
||||
setCensusSelected: Dispatch<boolean>,
|
||||
setLayerToggled: Dispatch<boolean>,
|
||||
}
|
||||
|
||||
const LayerSelector = ({censusSelected, setCensusSelected, setLayerToggled}:ILayerSelector) => {
|
||||
const intl = useIntl();
|
||||
|
||||
/**
|
||||
* At compile-time, the width/height returned by useWindowSize will be X. When the client requests the
|
||||
* app on run-time from CDN, and the app hydrates, reconcilation no longer occurs and the client is forced
|
||||
* to use X.
|
||||
*
|
||||
* To avoid this, we set the text as a state variable. We also create a useEffect that updates
|
||||
* that state whenenver the width changes.
|
||||
*
|
||||
*/
|
||||
const {width, height} = useWindowSize();
|
||||
const [censusText, setCensusText]= useState(EXPLORE_COPY.MAP.CENSUS_TRACT_LONG);
|
||||
const [tribalText, setTribalText]= useState(EXPLORE_COPY.MAP.TRIBAL_LANDS_LONG);
|
||||
|
||||
useEffect( () => {
|
||||
if (width > height) {
|
||||
setCensusText(EXPLORE_COPY.MAP.CENSUS_TRACT_LONG);
|
||||
setTribalText(EXPLORE_COPY.MAP.TRIBAL_LANDS_LONG);
|
||||
} else {
|
||||
setCensusText(EXPLORE_COPY.MAP.CENSUS_TRACT_SHORT);
|
||||
setTribalText(EXPLORE_COPY.MAP.TRIBAL_LANDS_SHORT);
|
||||
}
|
||||
}, [width]);
|
||||
|
||||
// Anytime the censusSelected state variable changes, set the LayerToggled state
|
||||
// variable
|
||||
useEffect( () => {
|
||||
setLayerToggled(true);
|
||||
}, [censusSelected]);
|
||||
|
||||
|
||||
// Handles toggle of tracts and tribal layer selection
|
||||
const buttonClickHandler = (event) => {
|
||||
if (event.target.id === 'census' && !censusSelected) {
|
||||
setCensusSelected(true);
|
||||
} else if (event.target.id === 'tribal' && censusSelected) {
|
||||
setCensusSelected(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.layerSelectorContainer}>
|
||||
{/* // Todo: set i18n here */}
|
||||
<label htmlFor="layer-group">Select layer</label>
|
||||
<ButtonGroup id="layer-group" type="segmented">
|
||||
<Button id="census" type="button" outline={!censusSelected} onClick={(e) => buttonClickHandler(e)}>
|
||||
{intl.formatMessage(censusText)}
|
||||
</Button>
|
||||
<Button id="tribal" type="button" outline={censusSelected} onClick={(e) => buttonClickHandler(e)}>
|
||||
{intl.formatMessage(tribalText)}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayerSelector;
|
|
@ -0,0 +1,83 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of the LayerSelector checks if component renders census tracts selected 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<label
|
||||
for="layer-group"
|
||||
>
|
||||
Select layer
|
||||
</label>
|
||||
<ul
|
||||
class="usa-button-group usa-button-group--segmented"
|
||||
id="layer-group"
|
||||
>
|
||||
<li
|
||||
class="usa-button-group__item"
|
||||
>
|
||||
<button
|
||||
class="usa-button"
|
||||
data-testid="button"
|
||||
id="census"
|
||||
type="button"
|
||||
>
|
||||
Census Tracts
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="usa-button-group__item"
|
||||
>
|
||||
<button
|
||||
class="usa-button usa-button--outline"
|
||||
data-testid="button"
|
||||
id="tribal"
|
||||
type="button"
|
||||
>
|
||||
Tribal Lands
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`rendering of the LayerSelector checks if component renders tribal selected 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<label
|
||||
for="layer-group"
|
||||
>
|
||||
Select layer
|
||||
</label>
|
||||
<ul
|
||||
class="usa-button-group usa-button-group--segmented"
|
||||
id="layer-group"
|
||||
>
|
||||
<li
|
||||
class="usa-button-group__item"
|
||||
>
|
||||
<button
|
||||
class="usa-button usa-button--outline"
|
||||
data-testid="button"
|
||||
id="census"
|
||||
type="button"
|
||||
>
|
||||
Census Tracts
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="usa-button-group__item"
|
||||
>
|
||||
<button
|
||||
class="usa-button"
|
||||
data-testid="button"
|
||||
id="tribal"
|
||||
type="button"
|
||||
>
|
||||
Tribal Lands
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
3
client/src/components/LayerSelector/index.tsx
Normal file
3
client/src/components/LayerSelector/index.tsx
Normal file
|
@ -0,0 +1,3 @@
|
|||
import LayerSelector from './LayerSelector';
|
||||
|
||||
export default LayerSelector;
|
|
@ -40,8 +40,9 @@ const LinkTypeWrapper = (props:ILinkTypeWrapper) => {
|
|||
|
||||
if (props.internal) {
|
||||
return (
|
||||
<Link to={`${url}`}
|
||||
className={props.className}
|
||||
<Link
|
||||
to={`${url}`}
|
||||
className={props.className ? `usa-link ${props.className}` : `usa-link`}
|
||||
>
|
||||
{props.linkText}
|
||||
</Link>
|
||||
|
|
|
@ -28,6 +28,7 @@ exports[`testing all link types tests external links same tab 1`] = `
|
|||
exports[`testing all link types tests internal links 1`] = `
|
||||
<DocumentFragment>
|
||||
<a
|
||||
class="usa-link"
|
||||
href="/en/methodology"
|
||||
>
|
||||
test link text
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
@use '../../styles/design-system.scss' as *;
|
||||
|
||||
.mapSearchContainer {
|
||||
/**
|
||||
Various breakpoint are being used to allow a consistent ratio
|
||||
of screen width between the search component and the geolocation
|
||||
component across all device sizes.
|
||||
*/
|
||||
|
||||
// styles for mobile-lg (480px) and greater widths,
|
||||
@include at-media('mobile-lg') {
|
||||
position: absolute;
|
||||
// top: units(4);
|
||||
left: units(1.5);
|
||||
width: 50%;
|
||||
z-index: 1;
|
||||
}
|
||||
// // width < 660
|
||||
// @include at-media-max("tablet") {
|
||||
// flex: 1 1 100%;
|
||||
// }
|
||||
|
||||
// styles for less than mobile-lg (480px)
|
||||
position: absolute;
|
||||
left: units(1.5);
|
||||
width: 90%;
|
||||
z-index: 1;
|
||||
// // 660 < width < 1024
|
||||
// @include at-media-max("desktop") {
|
||||
// @include at-media("tablet"){
|
||||
// flex: 1 1 56%;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // > 1024
|
||||
// @include at-media("desktop") {
|
||||
// flex: 1 1 72%;
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,11 @@ exports[`rendering of the MapSearch checks if component renders 1`] = `
|
|||
data-testid="button"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="usa-sr-only"
|
||||
>
|
||||
Search
|
||||
</span>
|
||||
<img
|
||||
alt="Search"
|
||||
class="usa-search__submit-icon"
|
||||
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTE1LjUgMTRoLS43OWwtLjI4LS4yN0MxNS40MSAxMi41OSAxNiAxMS4xMSAxNiA5LjUgMTYgNS45MSAxMy4wOSAzIDkuNSAzUzMgNS45MSAzIDkuNSA1LjkxIDE2IDkuNSAxNmMxLjYxIDAgMy4wOS0uNTkgNC4yMy0xLjU3bC4yNy4yOHYuNzlsNSA0Ljk5TDIwLjQ5IDE5bC00Ljk5LTV6bS02IDBDNy4wMSAxNCA1IDExLjk5IDUgOS41UzcuMDEgNSA5LjUgNSAxNCA3LjAxIDE0IDkuNSAxMS45OSAxNCA5LjUgMTR6Ii8+PC9zdmc+"
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
.showMessage {
|
||||
@include searchMessageLayout;
|
||||
display: block;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.hideMessage {
|
||||
|
|
199
client/src/components/MapTractLayers/MapTractLayers.tsx
Normal file
199
client/src/components/MapTractLayers/MapTractLayers.tsx
Normal file
|
@ -0,0 +1,199 @@
|
|||
import React, {useMemo} from 'react';
|
||||
import {Source, Layer} from 'react-map-gl';
|
||||
import {AnyLayer} from 'mapbox-gl';
|
||||
|
||||
// Contexts:
|
||||
import {useFlags} from '../../contexts/FlagContext';
|
||||
|
||||
import * as constants from '../../data/constants';
|
||||
import * as COMMON_COPY from '../../data/copy/common';
|
||||
|
||||
interface IMapTractLayers {
|
||||
selectedFeatureId: AnyLayer,
|
||||
selectedFeature: AnyLayer,
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will determine the URL for the map tiles. It will read in a string that will designate either
|
||||
* high or low tiles. It will allow to overide the URL to the pipeline staging tile URL via feature flag.
|
||||
* Lastly, it allows to set the tiles to be local or via the CDN as well.
|
||||
*
|
||||
* @param {string} tilesetName
|
||||
* @return {string}
|
||||
*/
|
||||
export const featureURLForTilesetName = (tilesetName: string): string => {
|
||||
const flags = useFlags();
|
||||
|
||||
const pipelineStagingBaseURL = `https://justice40-data.s3.amazonaws.com/data-pipeline-staging`;
|
||||
const XYZ_SUFFIX = '{z}/{x}/{y}.pbf';
|
||||
|
||||
if ('stage_hash' in flags) {
|
||||
// Check if the stage_hash is valid
|
||||
const regex = /^[0-9]{4}\/[a-f0-9]{40}$/;
|
||||
if (!regex.test(flags['stage_hash'])) {
|
||||
console.error(COMMON_COPY.CONSOLE_ERROR.STAGE_URL);
|
||||
}
|
||||
|
||||
return `${pipelineStagingBaseURL}/${flags['stage_hash']}/data/score/tiles/${tilesetName}/${XYZ_SUFFIX}`;
|
||||
} else {
|
||||
// The feature tile base URL and path can either point locally or the CDN.
|
||||
// This is selected based on the DATA_SOURCE env variable.
|
||||
const featureTileBaseURL = process.env.DATA_SOURCE === 'local' ?
|
||||
process.env.GATSBY_LOCAL_TILES_BASE_URL :
|
||||
process.env.GATSBY_CDN_TILES_BASE_URL;
|
||||
|
||||
const featureTilePath = process.env.DATA_SOURCE === 'local' ?
|
||||
process.env.GATSBY_DATA_PIPELINE_SCORE_PATH_LOCAL :
|
||||
process.env.GATSBY_1_0_SCORE_PATH;
|
||||
|
||||
return [
|
||||
featureTileBaseURL,
|
||||
featureTilePath,
|
||||
process.env.GATSBY_MAP_TILES_PATH,
|
||||
tilesetName,
|
||||
XYZ_SUFFIX,
|
||||
].join('/');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This component will return the appropriate source and layers for the census layer on the
|
||||
* map.
|
||||
*
|
||||
* There are two use cases here, eg, when the MapBox token is or isn't provided. When the token
|
||||
* is not provided, the open-source map will be rendered. When the open-source map is rendered
|
||||
* only the interactive layers are returned from this component. The reason being is that the
|
||||
* other layers are supplied by he getOSBaseMap function.
|
||||
*
|
||||
* @param {AnyLayer} selectedFeatureId
|
||||
* @param {AnyLayer} selectedFeature
|
||||
* @return {Style}
|
||||
*/
|
||||
const MapTractLayers = ({
|
||||
selectedFeatureId,
|
||||
selectedFeature,
|
||||
}: IMapTractLayers) => {
|
||||
const filter = useMemo(() => ['in', constants.GEOID_PROPERTY, selectedFeatureId], [selectedFeature]);
|
||||
|
||||
return process.env.MAPBOX_STYLES_READ_TOKEN ? (
|
||||
|
||||
// In this case the MapBox token is found and All source(s)/layer(s) are returned.
|
||||
<>
|
||||
<Source
|
||||
id={constants.LOW_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[featureURLForTilesetName('low')]}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_LOW}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_LOW}
|
||||
>
|
||||
|
||||
{/* Low zoom layer (static) - prioritized features only */}
|
||||
<Layer
|
||||
id={constants.LOW_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['>', constants.SCORE_PROPERTY_LOW, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.LOW_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY}}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_LOW}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_LOW}
|
||||
/>
|
||||
</Source>
|
||||
|
||||
{/* The high zoom source */}
|
||||
<Source
|
||||
id={constants.HIGH_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[featureURLForTilesetName('high')]}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_HIGH}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
>
|
||||
|
||||
{/* High zoom layer (static) - non-prioritized features only */}
|
||||
<Layer
|
||||
id={constants.HIGH_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['==', constants.SCORE_PROPERTY_HIGH, false]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-opacity': constants.NON_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
|
||||
{/* High zoom layer (static) - prioritized features only */}
|
||||
<Layer
|
||||
id={constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['==', constants.SCORE_PROPERTY_HIGH, true]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.HIGH_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
|
||||
{/* High zoom layer (static) - controls the border between features */}
|
||||
<Layer
|
||||
id={constants.FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.FEATURE_BORDER_WIDTH,
|
||||
'line-opacity': constants.FEATURE_BORDER_OPACITY,
|
||||
}}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_FEATURE_BORDER}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_FEATURE_BORDER}
|
||||
/>
|
||||
|
||||
{/* High zoom layer (dynamic) - border styling around the selected feature */}
|
||||
<Layer
|
||||
id={constants.SELECTED_FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={filter} // This filter filters out all other features except the selected feature.
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.SELECTED_FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.SELECTED_FEATURE_BORDER_WIDTH,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
</Source>
|
||||
</>
|
||||
): (
|
||||
|
||||
/**
|
||||
* In this case the MapBox token is NOT found and ONLY interactive source(s)/layer(s) are returned
|
||||
* In this case, the other layers (non-interactive) are provided by getOSBaseMap
|
||||
*/
|
||||
<Source
|
||||
id={constants.HIGH_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[featureURLForTilesetName('high')]}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_HIGH}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
>
|
||||
|
||||
{/* High zoom layer (dynamic) - border styling around the selected feature */}
|
||||
<Layer
|
||||
id={constants.SELECTED_FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={filter} // This filter filters out all other features except the selected feature.
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.SELECTED_FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.SELECTED_FEATURE_BORDER_WIDTH,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
</Source>
|
||||
);
|
||||
};
|
||||
|
||||
export default MapTractLayers;
|
3
client/src/components/MapTractLayers/index.tsx
Normal file
3
client/src/components/MapTractLayers/index.tsx
Normal file
|
@ -0,0 +1,3 @@
|
|||
import MapTractLayers from './MapTractLayers';
|
||||
|
||||
export default MapTractLayers;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue