diff --git a/package-lock.json b/package-lock.json
index 6e08a314db..c4436bc9ab 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3799,9 +3799,9 @@
}
},
"node_modules/@storybook/core-common/node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -5217,9 +5217,9 @@
}
},
"node_modules/@babel/helper-member-expression-to-functions/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -6357,9 +6357,9 @@
}
},
"node_modules/@babel/helper-remap-async-to-generator/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -6469,9 +6469,9 @@
}
},
"node_modules/@storybook/mdx1-csf/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -7075,9 +7075,9 @@
"license": "MIT"
},
"node_modules/@babel/plugin-transform-modules-systemjs/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -7124,9 +7124,9 @@
}
},
"node_modules/@babel/helper-simple-access/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -7262,9 +7262,9 @@
}
},
"node_modules/proxy-agent/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7789,9 +7789,9 @@
}
},
"node_modules/@babel/types": {
- "version": "7.26.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
- "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
+ "version": "7.26.3",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz",
+ "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
@@ -8188,9 +8188,9 @@
"license": "Unlicense"
},
"node_modules/@babel/traverse/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -8958,12 +8958,12 @@
"license": "ISC"
},
"node_modules/@babel/parser": {
- "version": "7.26.2",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz",
- "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==",
+ "version": "7.26.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz",
+ "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==",
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.26.0"
+ "@babel/types": "^7.26.3"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -9013,9 +9013,9 @@
}
},
"node_modules/pac-proxy-agent/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12202,9 +12202,9 @@
}
},
"node_modules/@babel/plugin-transform-async-generator-functions/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -15010,9 +15010,9 @@
"license": "MIT"
},
"node_modules/@babel/helper-module-imports/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -17710,13 +17710,13 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.26.2",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz",
- "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==",
+ "version": "7.26.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz",
+ "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==",
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.26.2",
- "@babel/types": "^7.26.0",
+ "@babel/parser": "^7.26.3",
+ "@babel/types": "^7.26.3",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
@@ -19669,9 +19669,9 @@
}
},
"node_modules/@lhci/server/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -21953,16 +21953,16 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz",
- "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
+ "version": "7.26.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz",
+ "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==",
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.25.9",
- "@babel/generator": "^7.25.9",
- "@babel/parser": "^7.25.9",
+ "@babel/code-frame": "^7.26.2",
+ "@babel/generator": "^7.26.3",
+ "@babel/parser": "^7.26.3",
"@babel/template": "^7.25.9",
- "@babel/types": "^7.25.9",
+ "@babel/types": "^7.26.3",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -28309,9 +28309,9 @@
}
},
"node_modules/socks-proxy-agent/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -32211,9 +32211,9 @@
}
},
"node_modules/@babel/core/node_modules/debug": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
- "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
diff --git a/src/_scss/elements/filters/_selectedFilterBtn.scss b/src/_scss/elements/filters/_selectedFilterBtn.scss
index 5ba0086c76..d8ff4643d8 100644
--- a/src/_scss/elements/filters/_selectedFilterBtn.scss
+++ b/src/_scss/elements/filters/_selectedFilterBtn.scss
@@ -2,19 +2,20 @@
.shown-filter-button {
background-color: $color-white;
border: 1px solid $color-gray-lighter;
- border-radius: rem(4);
+ border-radius: rem(2);
color: $color-gray;
font-size: $smallest-font-size;
- font-weight: normal;
- min-height: rem(31);
+ font-weight: $font-semibold;
+ min-height: rem(22);
height: auto;
- padding: rem(6) rem(10);
+ padding: rem(2) rem(4);
text-align: left;
width: auto;
max-width: 90%;
line-height: 1.3;
- margin-bottom: rem(2);
margin-top: rem(2);
+ margin-bottom: 0;
+ margin-right: rem(8);
@include display(flex);
@include align-items(center);
@@ -30,7 +31,7 @@
.close {
@include display(flex);
font-size: $small-font-size;
- padding: 0 rem(5) rem(1) rem(15);
+ padding: 0 0 0 rem(4);
}
&:hover {
background: lighten($color-cool-blue-lightest, 10%);
diff --git a/src/_scss/pages/recipient/_contentWrap.scss b/src/_scss/pages/recipient/_contentWrap.scss
index 54d41ff0d1..78a6cc084f 100644
--- a/src/_scss/pages/recipient/_contentWrap.scss
+++ b/src/_scss/pages/recipient/_contentWrap.scss
@@ -3,8 +3,6 @@
color: $color-base;
.recipient-section {
- padding: rem(30);
-
h3.recipient-section__title {
margin: 0;
font-size: $h3-font-size;
@@ -79,7 +77,7 @@
@include media($tablet-screen) {
@include flex(1 1 50%);
}
-
+
// this is all to make the borders gray and not doubled
// it's not ideal, but here we are
.recipient-section__details-table {
@@ -140,6 +138,10 @@
}
}
}
+
+ .recipient-section__viz.details {
+ margin-left: 0;
+ }
}
}
diff --git a/src/_scss/pages/recipient/_overview.scss b/src/_scss/pages/recipient/_overview.scss
index 3fd1fb06b6..235e24979c 100644
--- a/src/_scss/pages/recipient/_overview.scss
+++ b/src/_scss/pages/recipient/_overview.scss
@@ -25,6 +25,7 @@
}
}
.recipient-overview__content {
+ width:100%;
h3.recipient-overview__heading {
@include h4;
font-size: rem(19);
diff --git a/src/_scss/pages/recipient/_positioning.scss b/src/_scss/pages/recipient/_positioning.scss
index a9fb201632..064ec877ce 100644
--- a/src/_scss/pages/recipient/_positioning.scss
+++ b/src/_scss/pages/recipient/_positioning.scss
@@ -1,23 +1,14 @@
.recipient-content-wrapper {
- @include display(flex);
- @include align-items(flex-start);
width: 100%;
-
- .recipient-sidebar {
- display: none;
- margin-top: 0;
- // Evenly distribute the 30px space between the sidebar & content
- margin-right: rem(15);
- @include media($medium-screen) {
- display: block;
- @include flex(0 0 25%);
- }
+ padding: ($global-spacing-unit * 5) ($global-spacing-unit * 4) ($global-spacing-unit * 4) ($global-spacing-unit * 4);
+
+ @media (max-width: $tablet-screen) {
+ padding: ($global-spacing-unit * 5) ($global-spacing-unit * 2) ($global-spacing-unit * 2) ($global-spacing-unit * 2);
}
.recipient-content {
width: 100%;
- @include media($medium-screen) {
- @include flex(1 1 75%);
- }
+ max-width: rem(1400);
+ margin: auto;
}
}
diff --git a/src/_scss/pages/recipient/recipientPage.scss b/src/_scss/pages/recipient/recipientPage.scss
index 8c59618d53..a50a2f8eff 100644
--- a/src/_scss/pages/recipient/recipientPage.scss
+++ b/src/_scss/pages/recipient/recipientPage.scss
@@ -30,8 +30,6 @@
}
.main-content {
- @import "../../mixins/fullSectionWrap";
- @include fullSectionWrap(0,0);
padding: 0;
@import "./_positioning";
@import "../../components/pageLoading";
diff --git a/src/_scss/pages/search/_collapsibleSidebar.scss b/src/_scss/pages/search/_collapsibleSidebar.scss
index 363107b06b..6ed7d45903 100644
--- a/src/_scss/pages/search/_collapsibleSidebar.scss
+++ b/src/_scss/pages/search/_collapsibleSidebar.scss
@@ -1,23 +1,20 @@
@import '_searchFilter';
-$sidebar-width: 354px;
-$sidebar-width-closed: 32px;
-
@keyframes collapsible-sidebar-slideopen {
0% {
- width: $sidebar-width-closed;
+ width: 0%;
}
100% {
- width: $sidebar-width;
+ width: 100%;
}
}
@keyframes collapsible-sidebar-slideclose {
0% {
- width: $sidebar-width;
+ width: 100%;
}
100% {
- width: $sidebar-width-closed;
+ width: 0%;
}
}
@@ -34,11 +31,10 @@ $sidebar-width-closed: 32px;
}
.search-collapsible-sidebar-container {
- position: sticky;
+ position: fixed;
background-color: $color-white;
box-shadow: unset;
border-radius: unset;
- width: $sidebar-width;
.chevron {
margin: auto;
@@ -48,8 +44,9 @@ $sidebar-width-closed: 32px;
}
.collapsible-sidebar--toggle {
+ position: relative;
float: right;
- margin-right: -42px;
+ margin-right: -12px;
margin-top: 16px;
border-radius: 12px;
width: 24px;
@@ -61,38 +58,42 @@ $sidebar-width-closed: 32px;
align-items: center;
justify-content: center;
cursor: pointer;
+ z-index: 2;
}
.collapsible-sidebar {
- width: $sidebar-width;
margin-top: -40px !important; // TODO Keep here until we remove the legacy panel
border: 1px solid $gray-cool-10;
box-shadow: none;
border-radius: unset;
- padding: 0 rem(32);
&.opened:not(.is-initial-loaded) {
- -webkit-animation: collapsible-sidebar-slideopen 0.25s forwards;
- animation: collapsible-sidebar-slideopen 0.25s forwards;
+ // TODO: Adjust animations next sprint
+ //-webkit-animation: collapsible-sidebar-slideopen 0.25s forwards;
+ //animation: collapsible-sidebar-slideopen 0.25s forwards;
}
&:not(.opened) {
- animation: collapsible-sidebar-slideclose 0.25s forwards;
- -webkit-animation: collapsible-sidebar-slideclose 0.25s forwards;
+ // TODO: Adjust animations next sprint
+ //animation: collapsible-sidebar-slideclose 0.25s forwards;
+ //-webkit-animation: collapsible-sidebar-slideclose 0.25s forwards;
- .collapsible-sidebar-drilldown, .collapsible-sidebar--main-menu {
- overflow: hidden;
- white-space: nowrap;
+ .sidebar-bottom-submit, .search-filter__container, .collapsible-sidebar--header, .collapsible-sidebar--drilldown, .collapsible-sidebar--main-menu {
+ display: none;
}
}
+ .categories-list, .category-filter {
+ overflow-y: auto;
+ }
+
.collapsible-sidebar--header {
- margin: rem(16) 0;
- height: 24px;
+ padding: rem(16) rem(32);
font-size: 16px;
font-weight: 600;
line-height: 1.5;
color: $gray-90;
+ border-bottom: $gray-cool-10 1px solid;
}
.sidebar-bottom-submit {
@@ -124,6 +125,7 @@ $sidebar-width-closed: 32px;
.collapsible-sidebar--back-btn {
color: $blue-50;
cursor: pointer;
+
.chevron {
width: 6px;
height: 10px;
@@ -131,13 +133,28 @@ $sidebar-width-closed: 32px;
}
}
+ .categories-list-category-type {
+ color: $gray-90;
+ font-size: rem(10);
+ line-height: 1.5;
+ padding: rem(2) rem(6);
+ background-color: $gray-cool-5;
+ border-radius: rem(4);
+ width: fit-content;
+ margin-top: rem(32);
+
+ &:first-of-type {
+ margin-top: 0;
+ }
+ }
+
.categories-list-item-container {
margin-top: 16px;
padding-bottom: 4px;
min-height: 26px;
line-height: 1.5;
align-items: center;
- font-size: 12px;
+ font-size: $smallest-font-size;
color: $gray-90;
font-weight: $font-semibold;
border-bottom: solid 1px $gray-cool-10;
@@ -147,13 +164,47 @@ $sidebar-width-closed: 32px;
overflow-y: auto;
}
- .search-filter__content {
- margin: unset;
- }
-
.location-filter {
padding: 0 0 2rem 0;
}
}
+
+ .sidebar-bottom-submit {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ }
}
-}
\ No newline at end of file
+}
+
+.search-contents.v2 {
+ .collapsible-sidebar {
+ @media(min-width: $large-screen) {
+ width: 350px;
+ }
+
+ @media(min-width: $medium-screen) and (max-width: $large-screen - 1) {
+ width: 300px;
+ }
+ }
+
+ .full-search-sidebar {
+ display: none;
+ margin-right: rem(16);
+ @media(min-width: $large-screen) {
+ display: flex;
+ flex-basis: 350px;
+ }
+
+ @media(min-width: $medium-screen) and (max-width: $large-screen - 1) {
+ display: flex;
+ flex-basis: 300px;
+ }
+ }
+
+ .search-results-view-container {
+ width: 100%;
+ min-width: 0;
+ }
+}
+
diff --git a/src/_scss/pages/search/_searchFilter.scss b/src/_scss/pages/search/_searchFilter.scss
index 07b831f1e1..3bf5855b8a 100644
--- a/src/_scss/pages/search/_searchFilter.scss
+++ b/src/_scss/pages/search/_searchFilter.scss
@@ -1,14 +1,15 @@
.search-filter__container {
- border-top: solid 1px $gray-cool-10;
- margin-bottom: $global-margin * 2;
+ cursor: pointer;
+ &:not(:first-child) {
+ border-top: solid 1px $gray-cool-10;
+ }
+ padding: $global-margin * 2 $global-margin * 4;
.search-filter__content {
- margin: rem(16) 0;
height: rem(91);
.search-filter__top-row {
display: flex;
- margin-top: $global-margin * 2;
.search-filter__top-row-icon-container {
display: flex;
@@ -34,7 +35,6 @@
font-weight: $font-semibold;
line-height: 1.5;
color: $theme-color-headline;
- cursor: pointer;
}
.search-filter__top-row-selected-container {
diff --git a/src/_scss/pages/search/_searchSubmit.scss b/src/_scss/pages/search/_searchSubmit.scss
index 2e6f13458f..6eb1d9b3c1 100644
--- a/src/_scss/pages/search/_searchSubmit.scss
+++ b/src/_scss/pages/search/_searchSubmit.scss
@@ -1,5 +1,5 @@
.sidebar-submit {
- padding: rem(15) rem(25);
+ padding: rem(8) rem(32);
.screen-reader-submit-header {
position:absolute;
diff --git a/src/_scss/pages/search/_searchv2.scss b/src/_scss/pages/search/_searchv2.scss
index cf11e92925..6beddba456 100644
--- a/src/_scss/pages/search/_searchv2.scss
+++ b/src/_scss/pages/search/_searchv2.scss
@@ -1,5 +1,4 @@
.usa-da-search-page.v2 #main-content .search-contents {
- width: 1620px !important; //TODO: Remove after search 2.0 is released
- max-width: 1620px !important; //TODO: Remove after search 2.0 is released
+ max-width: 1600px !important; //TODO: Remove after search 2.0 is released
}
\ No newline at end of file
diff --git a/src/_scss/pages/search/filters/recipient/recipient.scss b/src/_scss/pages/search/filters/recipient/recipient.scss
index b86c2c47f3..e8c3563da9 100644
--- a/src/_scss/pages/search/filters/recipient/recipient.scss
+++ b/src/_scss/pages/search/filters/recipient/recipient.scss
@@ -97,6 +97,16 @@
}
}
+ .recipient-filter-message-container {
+ font-size: rem(30);
+ text-align: center;
+ margin-top: $global-margin;
+ .recipient-filter-message-container__text {
+ font-size: 2rem;
+ padding-bottom: 2rem;
+ }
+ }
+
.recipient-filter-item-wrap {
padding: 0;
diff --git a/src/_scss/pages/search/filters/timePeriod/timePeriodNew.scss b/src/_scss/pages/search/filters/timePeriod/timePeriodNew.scss
index 206f52384f..ef6b0ffe5e 100644
--- a/src/_scss/pages/search/filters/timePeriod/timePeriodNew.scss
+++ b/src/_scss/pages/search/filters/timePeriod/timePeriodNew.scss
@@ -294,6 +294,7 @@
.selected-filters {
@include selected-filter-wrap;
+ display: flex;
}
}
}
diff --git a/src/_scss/pages/state/_contentWrap.scss b/src/_scss/pages/state/_contentWrap.scss
index feb20d235e..be2f33a8d2 100644
--- a/src/_scss/pages/state/_contentWrap.scss
+++ b/src/_scss/pages/state/_contentWrap.scss
@@ -3,8 +3,6 @@
color: $color-base;
.state-section {
- padding: rem(30);
-
h3.state-section__title {
margin: 0;
font-size: $h3-font-size;
diff --git a/src/_scss/pages/state/_positioning.scss b/src/_scss/pages/state/_positioning.scss
index d17ccff628..7011fe0b12 100644
--- a/src/_scss/pages/state/_positioning.scss
+++ b/src/_scss/pages/state/_positioning.scss
@@ -1,23 +1,14 @@
.state-content-wrapper {
- @include display(flex);
- @include align-items(flex-start);
width: 100%;
+ padding: ($global-spacing-unit * 5) ($global-spacing-unit * 4) ($global-spacing-unit * 4) ($global-spacing-unit * 4);
- .state-sidebar {
- display: none;
- margin-top: 0;
- // Evenly distribute the 30px space between the sidebar & content
- margin-right: rem(15);
- @include media($medium-screen) {
- display: block;
- @include flex(0 0 25%);
- }
+ @media (max-width: $tablet-screen) {
+ padding: ($global-spacing-unit * 5) ($global-spacing-unit * 2) ($global-spacing-unit * 2) ($global-spacing-unit * 2);
}
.state-content {
width: 100%;
- @include media($medium-screen) {
- @include flex(1 1 75%);
- }
+ max-width: rem(1400);
+ margin: auto;
}
-}
\ No newline at end of file
+}
diff --git a/src/_scss/pages/state/statePage.scss b/src/_scss/pages/state/statePage.scss
index dec95959ca..b55b786a4c 100644
--- a/src/_scss/pages/state/statePage.scss
+++ b/src/_scss/pages/state/statePage.scss
@@ -26,8 +26,8 @@
}
.main-content {
- @import "../../mixins/fullSectionWrap";
- @include fullSectionWrap(0,0);
+ //@import "../../mixins/fullSectionWrap";
+ //@include fullSectionWrap(0,0);
padding: 0;
@import "./_positioning";
diff --git a/src/js/components/recipient/RecipientOverview.jsx b/src/js/components/recipient/RecipientOverview.jsx
index 7aff54a1db..10ba35377a 100644
--- a/src/js/components/recipient/RecipientOverview.jsx
+++ b/src/js/components/recipient/RecipientOverview.jsx
@@ -7,7 +7,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Set } from 'immutable';
import { isCancel } from 'axios';
-import { TooltipWrapper, SectionHeader } from 'data-transparency-ui';
+import { TooltipWrapper, SectionHeader, FlexGridCol, FlexGridRow } from 'data-transparency-ui';
import { initialState as defaultFilters } from 'redux/reducers/search/searchFiltersReducer';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Link } from 'react-router-dom';
@@ -165,9 +165,10 @@ const RecipientOverview = (props) => {
getSelectedHash(recipient.uei);
};
return (
-
+
{recipient.name}
{viewAlternateNames}
@@ -185,7 +186,7 @@ const RecipientOverview = (props) => {
{viewChildren}
-
+
Total Awarded Amount
@@ -210,9 +211,9 @@ const RecipientOverview = (props) => {
-
+
-
+
Details
@@ -248,10 +249,10 @@ const RecipientOverview = (props) => {
-
+
-
+
);
};
diff --git a/src/js/components/recipient/spendingOverTime/RecipientTimeVisualizationSection.jsx b/src/js/components/recipient/spendingOverTime/RecipientTimeVisualizationSection.jsx
index b31a4cfc91..431663d1b2 100644
--- a/src/js/components/recipient/spendingOverTime/RecipientTimeVisualizationSection.jsx
+++ b/src/js/components/recipient/spendingOverTime/RecipientTimeVisualizationSection.jsx
@@ -7,7 +7,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { throttle } from 'lodash';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { SectionHeader } from "data-transparency-ui";
+import { SectionHeader, FlexGridRow } from "data-transparency-ui";
import TimeVisualizationPeriodButton from 'components/search/newResultsView/time/TimeVisualizationPeriodButton';
import RecipientTimeVisualization from './RecipientTimeVisualization';
@@ -55,7 +55,7 @@ export default class RecipientTimeVisualizationSection extends React.Component {
render() {
return (
-
+
);
}
}
diff --git a/src/js/components/recipient/topFive/TopFiveSection.jsx b/src/js/components/recipient/topFive/TopFiveSection.jsx
index f5118e83ed..2c79e9b61f 100644
--- a/src/js/components/recipient/topFive/TopFiveSection.jsx
+++ b/src/js/components/recipient/topFive/TopFiveSection.jsx
@@ -8,7 +8,7 @@ import React from 'react';
import { recipientCategories as topCategories } from 'dataMapping/topCategories';
import TopFiveContainer from 'containers/recipient/topFive/TopFiveContainer';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { SectionHeader } from "data-transparency-ui";
+import { SectionHeader, FlexGridRow } from "data-transparency-ui";
const TopFiveSection = () => {
const content = topCategories.map((category) => (
@@ -18,7 +18,7 @@ const TopFiveSection = () => {
));
return (
-
+
);
};
diff --git a/src/js/components/search/SearchPage.jsx b/src/js/components/search/SearchPage.jsx
index 1e88a4c5e9..a5e2417070 100644
--- a/src/js/components/search/SearchPage.jsx
+++ b/src/js/components/search/SearchPage.jsx
@@ -63,7 +63,6 @@ const SearchPage = ({
const [isMobile, setIsMobile] = useState(window.innerWidth < mediumScreen);
const [fullSidebar, setFullSidebar] = useState(false);
-
const dispatch = useDispatch();
const getSlugWithHash = () => {
@@ -140,6 +139,7 @@ const SearchPage = ({
useEffect(() => {
setFullSidebar();
+ dispatch(setSearchViewSubaward(false));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
diff --git a/src/js/components/search/collapsibleSidebar/CategoryFilter.jsx b/src/js/components/search/collapsibleSidebar/CategoryFilter.jsx
index ecb1363dc0..1eb8b46484 100644
--- a/src/js/components/search/collapsibleSidebar/CategoryFilter.jsx
+++ b/src/js/components/search/collapsibleSidebar/CategoryFilter.jsx
@@ -4,7 +4,7 @@
// eslint-disable-next-line no-unused-vars
import React from "react";
import PropTypes from 'prop-types';
-import SearchFilter from "./SearchFilter";
+import CategoryHeader from "./CategoryHeader";
const propTypes = {
component: PropTypes.object
@@ -14,14 +14,14 @@ const CategoryFilter = ({
iconBackgroundColor, iconName, iconColor, component, title, description, height
}) => (
<>
-
-
- {component}
+
>
);
diff --git a/src/js/components/search/collapsibleSidebar/CategoryHeader.jsx b/src/js/components/search/collapsibleSidebar/CategoryHeader.jsx
new file mode 100644
index 0000000000..53fffe1fbc
--- /dev/null
+++ b/src/js/components/search/collapsibleSidebar/CategoryHeader.jsx
@@ -0,0 +1,91 @@
+/**
+ * CategoryHeader.jsx
+ * Created by Brian Petway 09/30/2024
+ */
+
+import React, { useEffect, useState } from 'react';
+import PropTypes from "prop-types";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+const propTypes = {
+ iconName: PropTypes.string,
+ iconColor: PropTypes.string,
+ iconBackgroundColor: PropTypes.string,
+ title: PropTypes.string,
+ description: PropTypes.string,
+ itemCount: PropTypes.number,
+ selectedItems: PropTypes.array,
+ selectCategory: PropTypes.func,
+ isClickable: PropTypes.bool,
+ showDescription: PropTypes.bool
+};
+
+const CategoryHeader = ({
+ item,
+ iconName,
+ iconColor,
+ iconBackgroundColor,
+ title,
+ description,
+ selectCategory,
+ isClickable
+}) => {
+ const [content, setContent] = useState();
+
+ const innerContent = (
+
+
+
+
+
+
+ {/*
*/}
+ {/*
{itemCount} selected
*/}
+ {/*
*/}
+
+
{description}
+ {/*
*/}
+ {/* {selectedItems.map((selectedItem) => (*/}
+ {/*
{selectedItem}
*/}
+ {/* ))}*/}
+ {/*
*/}
+
+ );
+
+ const filterButton = (
+
+ { innerContent }
+
);
+
+ const clickableFilterButton = (
+
selectCategory(e, item)}
+ onKeyDown={(e) => (e.key === "Enter" ? selectCategory(e, item) : '')}
+ tabIndex={0}
+ role="button">
+ { innerContent }
+
+
);
+
+ useEffect(() => {
+ if (isClickable) {
+ setContent(clickableFilterButton);
+ }
+ else {
+ setContent(filterButton);
+ }
+ }, [isClickable]);
+
+
+ return (<>{ content }>);
+};
+
+CategoryHeader.propTypes = propTypes;
+export default CategoryHeader;
diff --git a/src/js/components/search/collapsibleSidebar/CateogriesList.jsx b/src/js/components/search/collapsibleSidebar/CateogriesList.jsx
index e5ec409944..2c9c9325b8 100644
--- a/src/js/components/search/collapsibleSidebar/CateogriesList.jsx
+++ b/src/js/components/search/collapsibleSidebar/CateogriesList.jsx
@@ -4,7 +4,7 @@
import React from "react";
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import SearchFilter from "./SearchFilter";
+import CategoryHeader from "./CategoryHeader";
const propTypes = {
categories: PropTypes.object,
@@ -12,31 +12,77 @@ const propTypes = {
};
const CategoriesList = ({
- categories, setLevel3, iconBackgroundColor, iconName, iconColor, title, description, height
+ categories,
+ setLevel3,
+ iconBackgroundColor,
+ iconName,
+ iconColor,
+ title,
+ description,
+ height
}) => (
-
-
+
-
- {categories.map((item) => (
-
setLevel3(e, item.component)}
- onKeyUp={((e) => (e.key === "Enter" ? setLevel3(e, item.component) : ''))}
- role="button"
- tabIndex={0}>
-
-
- ))}
+
+
+ {categories.map((item) => {
+ if (item?.categoryType) {
+ return (
+ <>
+
+ {item.categoryType}
+
+ {
+ item.categories.map((category) => (
+
setLevel3(e, category)}
+ onKeyUp={
+ ((e) => (
+ e.key === "Enter" ? setLevel3(e, category.component) : ''
+ ))
+ }
+ role="button"
+ tabIndex={0}>
+
+
+ ))
+ }
+ >
+ );
+ }
+
+ return (
+
setLevel3(e, item)}
+ onKeyUp={((e) => (e.key === "Enter" ? setLevel3(e, item.component) : ''))}
+ role="button"
+ tabIndex={0}>
+
+
+ );
+ })}
+
-
+ >
);
CategoriesList.propTypes = propTypes;
diff --git a/src/js/components/search/collapsibleSidebar/CollapsibleSidebar.jsx b/src/js/components/search/collapsibleSidebar/CollapsibleSidebar.jsx
new file mode 100644
index 0000000000..df875d9b52
--- /dev/null
+++ b/src/js/components/search/collapsibleSidebar/CollapsibleSidebar.jsx
@@ -0,0 +1,218 @@
+/**
+ * CollapsibleSidebar.jsx
+ * Created by Andrea Blackwell 11/05/2024
+ **/
+
+import React, { useEffect, useState } from 'react';
+import { FilterCategoryTree } from "dataMapping/search/searchFilterCategories";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { throttle } from "lodash";
+
+import SearchSidebarSubmitContainer from "../../../containers/search/SearchSidebarSubmitContainer";
+import SearchSidebarDrilldown from "./SearchSidebarDrilldown";
+import SearchSidebarMainMenu from "./SearchSidebarMainMenu";
+
+const CollapsibleSidebar = () => {
+ const [isOpened, setIsOpened] = useState(true);
+ const [drilldown, setDrilldown] = useState(null);
+ const [isDrilldown, setIsDrilldown] = useState(false);
+ const [selectedCategory, setSelectedCategory] = useState(null);
+ const [currentLevel, setCurrentLevel] = useState(1);
+ const [initialPageLoad, setInitialPageLoad] = useState(true);
+ const [windowWidth, setWindowWidth] = useState();
+ const [windowHeight, setWindowHeight] = useState();
+ const [sidebarHeight, setSidebarHeight] = useState();
+
+ const toggleOpened = (e) => {
+ e.preventDefault();
+ setIsOpened((prevState) => !prevState);
+ };
+
+ const setLevel2 = (e, item) => {
+ e.preventDefault();
+ setSelectedCategory(item);
+ setDrilldown(FilterCategoryTree[item?.categoryKey]);
+ setIsDrilldown(true);
+ setCurrentLevel(2);
+ };
+
+ const setLevel3 = (e, item) => {
+ e.preventDefault();
+ setDrilldown(item);
+ setIsDrilldown(true);
+ setCurrentLevel(3);
+ };
+
+ const goBack = (e) => {
+ if (currentLevel === 2) {
+ e.preventDefault();
+ setDrilldown(null);
+ setCurrentLevel(1);
+ setIsDrilldown(false);
+ }
+ else if (currentLevel === 3) {
+ setDrilldown(selectedCategory[FilterCategoryTree[selectedCategory?.categoryKey]]);
+ setCurrentLevel(2);
+ }
+ };
+
+ useEffect(() => {
+ if (isOpened) {
+ if (document.querySelector(".full-search-sidebar")) {
+ if (windowWidth < 991 && windowWidth < 1200) {
+ document.querySelector(".full-search-sidebar").style.width = "unset";
+ document.querySelector(".full-search-sidebar").style.flexBasis = "282px";
+ document.querySelector(".collapsible-sidebar").style.width = "282px";
+ }
+ else if (windowWidth > 1199) {
+ document.querySelector(".full-search-sidebar").style.width = "unset";
+ document.querySelector(".full-search-sidebar").style.flexBasis = "332px";
+ document.querySelector(".collapsible-sidebar").style.width = "332px";
+ }
+ }
+ }
+ else if (document.querySelector(".full-search-sidebar")) {
+ document.querySelector(".full-search-sidebar").style.width = "0";
+ document.querySelector(".full-search-sidebar").style.flexBasis = "0";
+ document.querySelector(".collapsible-sidebar").style.width = "0";
+ }
+ }, [isOpened, windowWidth]);
+
+ useEffect(() => {
+ if (!isOpened && initialPageLoad) {
+ setInitialPageLoad(false);
+ }
+ }, [initialPageLoad, isOpened]);
+
+ const checkInView = (el) => {
+ const bbox = el.getBoundingClientRect();
+
+ const intersection = {
+ top: Math.max(0, bbox.top),
+ left: Math.max(0, bbox.left),
+ bottom: Math.min(window.innerHeight, bbox.bottom),
+ right: Math.min(window.innerWidth, bbox.right)
+ };
+
+ return (intersection.bottom - intersection.top);
+ };
+
+ const resizeSidebarWithStickyBar = (footerInView, headingInView, headingPadding, inPanelNonScrollableEls) => {
+ if (footerInView < 0) {
+ setWindowHeight((window.innerHeight - headingInView) + headingPadding);
+ setSidebarHeight(((window.innerHeight - headingInView) - inPanelNonScrollableEls) + headingPadding);
+ }
+ else {
+ // Hide side search by... if only a small part of the sidebar is in view
+ const newSidebarHeight = (((window.innerHeight - headingInView) - inPanelNonScrollableEls) - footerInView) + headingPadding;
+ if (newSidebarHeight < 1) {
+ document.querySelector(".collapsible-sidebar--header").style.display = "none";
+ }
+ else {
+ document.querySelector(".collapsible-sidebar--header").style.display = "block";
+ }
+
+ setWindowHeight(((window.innerHeight - headingInView) - footerInView) + headingPadding);
+ setSidebarHeight(newSidebarHeight);
+ }
+ };
+
+ const resizeSidebarWithFullHeader = (fullHeader, inPanelNonScrollableEls) => {
+ setWindowHeight((window.innerHeight - fullHeader) + window.scrollY);
+ setSidebarHeight(((window.innerHeight - fullHeader) - inPanelNonScrollableEls) + window.scrollY);
+ };
+
+ const handleScroll = throttle(() => {
+ // TODO: Remove upon completion of sidepanel - 581.63 is the height of the footer at 1839 px browser width
+ const footerEl = document.querySelector("footer");
+ const footerInView = checkInView(footerEl) + 48;
+ const topStickyBarEl = document.querySelector(".usda-page-header");
+ const topStickyBarBbox = topStickyBarEl.getBoundingClientRect();
+ const top = checkInView(topStickyBarEl) < 0 ? 0 : topStickyBarBbox.bottom;
+ const headingPadding = 40;
+ const headingInView = top + headingPadding;
+ const fullHeader = 148;
+ const inPanelNonScrollableEls = 172;
+
+ document.querySelector(".search-collapsible-sidebar-container").style.top = `${headingInView}px`;
+
+ if (topStickyBarEl?.classList?.contains("usda-page-header--sticky")) {
+ resizeSidebarWithStickyBar(footerInView, headingInView, headingPadding, inPanelNonScrollableEls);
+ }
+ else if (top !== 0) {
+ resizeSidebarWithFullHeader(fullHeader, inPanelNonScrollableEls);
+ }
+ }, 50);
+
+ const keyHandler = (e, func) => {
+ e.preventDefault();
+ if (e.key === "Enter") {
+ func(e);
+ }
+ };
+
+ const handleResize = throttle(() => {
+ const newWidth = window.innerWidth;
+ if (windowWidth !== newWidth) {
+ setWindowWidth(newWidth);
+ }
+ }, 50);
+
+ useEffect(() => {
+ handleScroll();
+ window.addEventListener('scroll', (e) => handleScroll(e));
+
+ return () => {
+ window.removeEventListener('scroll', handleScroll);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ useEffect(() => {
+ handleResize();
+ window.addEventListener('resize', (e) => handleResize(e));
+ return () => window.removeEventListener('resize', handleResize);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ return (
+
+
+
toggleOpened(e)}
+ onKeyDown={(e) => keyHandler(e, toggleOpened)}
+ role="button"
+ tabIndex="0">
+ {isOpened ?
+
+ :
+
+ }
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default CollapsibleSidebar;
diff --git a/src/js/components/search/collapsibleSidebar/SearchFilter.jsx b/src/js/components/search/collapsibleSidebar/SearchFilter.jsx
deleted file mode 100644
index 5a8265e327..0000000000
--- a/src/js/components/search/collapsibleSidebar/SearchFilter.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * SearchFilter.jsx
- * Created by Brian Petway 09/30/2024
- */
-
-import React from 'react';
-import PropTypes from "prop-types";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-
-const propTypes = {
- iconName: PropTypes.string,
- iconColor: PropTypes.string,
- iconBackgroundColor: PropTypes.string,
- title: PropTypes.string,
- description: PropTypes.string,
- itemCount: PropTypes.number,
- selectedItems: PropTypes.array,
- selectCategory: PropTypes.func
-};
-
-const SearchFilter = ({
- item,
- iconName,
- iconColor,
- iconBackgroundColor,
- title,
- description,
- selectCategory
-}) => (
-
-
-
-
-
-
-
-
selectCategory(e, item)}
- OnKeyDown={(e) => (e.key === "Enter" ? selectCategory(e, item) : '')}
- tabIndex={0}
- role="button">{title}
-
-
- {/*
*/}
- {/*
{itemCount} selected
*/}
- {/*
*/}
-
-
{description}
- {/*
*/}
- {/* {selectedItems.map((selectedItem) => (*/}
- {/*
{selectedItem}
*/}
- {/* ))}*/}
- {/*
*/}
-
-
-);
-
-SearchFilter.propTypes = propTypes;
-export default SearchFilter;
diff --git a/src/js/components/search/collapsibleSidebar/SearchPagev2.jsx b/src/js/components/search/collapsibleSidebar/SearchPagev2.jsx
index b258b037f1..c69db1a592 100644
--- a/src/js/components/search/collapsibleSidebar/SearchPagev2.jsx
+++ b/src/js/components/search/collapsibleSidebar/SearchPagev2.jsx
@@ -6,7 +6,7 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { throttle } from 'lodash';
-import { DownloadIconButton, ShareIcon, FlexGridRow, FlexGridCol } from 'data-transparency-ui';
+import { DownloadIconButton, ShareIcon, FlexGridCol } from 'data-transparency-ui';
import { Helmet } from 'react-helmet';
import { handleShareOptionClick, getBaseUrl } from 'helpers/socialShare';
@@ -26,7 +26,7 @@ import SubawardDropdown from "../SubawardDropdown";
import { setSearchViewSubaward } from "../../../redux/actions/search/searchViewActions";
import ResultsView from "../newResultsView/ResultsView";
import Button from "../../sharedComponents/buttons/Button";
-import SearchSidebarv2 from "./SearchSidebarv2";
+import CollapsibleSidebar from "./CollapsibleSidebar";
import PageFeatureFlag from "../../sharedComponents/PageFeatureFlag";
require('pages/search/searchPage.scss');
@@ -142,7 +142,7 @@ const SearchPage = ({
useEffect(() => {
setSearchv2(true);
- setFullSidebar();
+ setFullSidebar();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -172,13 +172,13 @@ const SearchPage = ({
filters={appliedFilters}>
-
-
+
+
{fullSidebar}
{isMobile === false && searchv2 === false ?
: ''}
-
+
{
+ const keyHandler = (e, func) => {
+ e.preventDefault();
+ if (e.key === "Enter") {
+ func(e);
+ }
+ };
+
+ return (
+
+
+
goBack(e)}
+ onKeyDown={(e) => keyHandler(e, goBack)}
+ role="button"
+ tabIndex="0">
+ Back
+
+
+
+ {list && }
+
+ {filter && }
+
+
);
+};
+
+SearchSidebarDrilldown.propTypes = propTypes;
+export default SearchSidebarDrilldown;
diff --git a/src/js/components/search/collapsibleSidebar/SearchSidebarMainMenu.jsx b/src/js/components/search/collapsibleSidebar/SearchSidebarMainMenu.jsx
new file mode 100644
index 0000000000..c0a6ad8409
--- /dev/null
+++ b/src/js/components/search/collapsibleSidebar/SearchSidebarMainMenu.jsx
@@ -0,0 +1,35 @@
+import React from "react";
+import PropTypes from 'prop-types';
+import { SearchFilterCategories } from "dataMapping/search/searchFilterCategories";
+import CategoryHeader from "./CategoryHeader";
+
+const propTypes = {
+ isDrilldown: PropTypes.bool,
+ sidebarHeight: PropTypes.number,
+ setLevel2: PropTypes.func
+};
+
+const SearchSidebarMainMenu = ({ isDrilldown, sidebarHeight, setLevel2 }) => (
+
+
+ Search by...
+
+
+ {SearchFilterCategories.map((item) => ())}
+
+
+);
+
+SearchSidebarMainMenu.propTypes = propTypes;
+export default SearchSidebarMainMenu;
diff --git a/src/js/components/search/collapsibleSidebar/SearchSidebarv2.jsx b/src/js/components/search/collapsibleSidebar/SearchSidebarv2.jsx
deleted file mode 100644
index 8e7d24570e..0000000000
--- a/src/js/components/search/collapsibleSidebar/SearchSidebarv2.jsx
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * SearchSidebarv2.jsx
- * Created by Andrea Blackwell 11/05/2024
- **/
-
-import React, { useEffect, useState } from 'react';
-import { SearchFilterCategories, FilterCategoryTree } from "dataMapping/search/newSearchFilterCategories";
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { throttle } from "lodash";
-
-import SearchFilter from "./SearchFilter";
-import { SearchSidebarSubmitContainer } from "../../../containers/search/SearchSidebarSubmitContainer";
-import CategoriesList from "./CateogriesList";
-import CategoryFilter from "./CategoryFilter";
-
-const SearchSidebar = () => {
- const [isOpened, setIsOpened] = useState(true);
- const [drilldown, setDrilldown] = useState(null);
- const [isDrilldown, setIsDrilldown] = useState(false);
- const [selectedCategory, setSelectedCategory] = useState(null);
- const [currentLevel, setCurrentLevel] = useState(1);
- const [initialPageLoad, setInitialPageLoad] = useState(true);
- const [windowWidth, setWindowWidth] = useState();
- const [windowHeight, setWindowHeight] = useState();
- const [sidebarHeight, setSidebarHeight] = useState();
- const toggleOpened = (e) => {
- e.preventDefault();
- setIsOpened((prevState) => !prevState);
- };
-
- const setLevel2 = (e, item) => {
- e.preventDefault();
- setSelectedCategory(item);
- setDrilldown(FilterCategoryTree[item?.categoryKey]);
- setIsDrilldown(true);
- setCurrentLevel(2);
- };
-
- const setLevel3 = (e, component) => {
- e.preventDefault();
- setDrilldown(component);
- setIsDrilldown(true);
- setCurrentLevel(3);
- };
-
- const goBack = (e) => {
- if (currentLevel === 2) {
- e.preventDefault();
- setDrilldown(null);
- setCurrentLevel(1);
- setIsDrilldown(false);
- }
- else if (currentLevel === 3) {
- setDrilldown(selectedCategory[FilterCategoryTree[selectedCategory?.categoryKey]]);
- setCurrentLevel(2);
- }
- };
-
- const keyHandler = (e, func) => {
- e.preventDefault();
- if (e.key === "Enter") {
- func(e);
- }
- };
-
- useEffect(() => {
- if (!isOpened && initialPageLoad) {
- setInitialPageLoad(false);
- }
- }, [initialPageLoad, isOpened]);
-
- const handleScroll = throttle(() => {
- const element = document.querySelector(".usda-page-header");
- if (element?.classList?.contains("usda-page-header--sticky")) {
- setWindowHeight(window.innerHeight - 100);
- setSidebarHeight(window.innerHeight - 100 - 178);
- }
- else {
- setWindowHeight(window.innerHeight - 198);
- setSidebarHeight(window.innerHeight - 198 - 178);
- }
- }, 50);
-
- useEffect(() => {
- setWindowHeight(window.innerHeight - 198);
- setSidebarHeight(window.innerHeight - 198 - 178);
- window.addEventListener('scroll', handleScroll);
- return () => window.removeEventListener('scroll', handleScroll);
- }, [handleScroll]);
-
- useEffect(() => {
- const handleResize = throttle(() => {
- const newWidth = window.innerWidth;
- if (windowWidth !== newWidth) {
- setWindowWidth(newWidth);
- }
- }, 50);
- window.addEventListener('resize', handleResize);
- return () => window.removeEventListener('resize', handleResize);
- }, [windowWidth]);
-
- return (
-
-
-
toggleOpened(e)}
- onKeyDown={(e) => keyHandler(e, toggleOpened)}
- role="button"
- tabIndex="0">
- {isOpened ?
-
- :
-
- }
-
-
-
-
goBack(e)}
- onKeyDown={(e) => keyHandler(e, goBack)}
- role="button"
- tabIndex="0">
- Back
-
-
- {drilldown?.children &&
}
-
- {drilldown?.component &&
}
-
-
-
-
- Search by...
-
-
- {SearchFilterCategories.map((item) => ())}
-
-
-
-
-
-
-
);
-};
-
-export default SearchSidebar;
diff --git a/src/js/components/search/filters/recipient/RecipientResultsContainer.jsx b/src/js/components/search/filters/recipient/RecipientResultsContainer.jsx
index b577529fdf..600eadfb12 100644
--- a/src/js/components/search/filters/recipient/RecipientResultsContainer.jsx
+++ b/src/js/components/search/filters/recipient/RecipientResultsContainer.jsx
@@ -5,6 +5,7 @@
import React, { useEffect, useState, useRef } from 'react';
import PropTypes from "prop-types";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as SearchHelper from 'helpers/searchHelper';
import { EntityDropdownAutocomplete } from "../location/EntityDropdownAutocomplete";
import PrimaryCheckboxType from "../../../sharedComponents/checkbox/PrimaryCheckboxType";
@@ -17,6 +18,7 @@ const propTypes = {
const RecipientResultsContainer = ({ selectedRecipients, updateSelectedRecipients }) => {
const [recipients, setRecipients] = useState([]);
const [searchString, setSearchString] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
const recipientRequest = useRef();
@@ -43,11 +45,15 @@ const RecipientResultsContainer = ({ selectedRecipients, updateSelectedRecipient
recipientRequest.current.cancel();
}
- recipientRequest.current = SearchHelper.fetchRecipients();
-
+ const paramObj = {
+ limit: 100
+ };
+ recipientRequest.current = SearchHelper.fetchRecipients(paramObj);
+ setIsLoading(true);
recipientRequest.current.promise
.then((res) => {
setRecipients(res.data.results);
+ setIsLoading(false);
});
};
@@ -58,14 +64,15 @@ const RecipientResultsContainer = ({ selectedRecipients, updateSelectedRecipient
const paramObj = {
search_text: term,
- limit: 50
+ limit: 100
};
recipientRequest.current = SearchHelper.fetchRecipientsAutocomplete(paramObj);
-
+ setIsLoading(true);
recipientRequest.current.promise
.then((res) => {
setRecipients(res.data.results);
+ setIsLoading(false);
});
};
@@ -83,6 +90,13 @@ const RecipientResultsContainer = ({ selectedRecipients, updateSelectedRecipient
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchString]);
+ const loadingIndicator = (
+
+
+
Loading your data...
+
+ );
+
return (
<>
-
-
- { recipients.toSorted((a, b) => (a.name?.toUpperCase() < b.name?.toUpperCase() ? -1 : 1)).map((recipient) => (
-
-
UEI: {recipient.uei ? recipient.uei : 'Not provided'})}
- value={{
- name: recipient.name ? recipient.name : recipient.recipient_name,
- uei: recipient.uei,
- duns: recipient.duns ? recipient.duns : null
- }}
- key={recipient.uei}
- toggleCheckboxType={toggleRecipient}
- selectedCheckboxes={selectedRecipients} />
-
-
Legacy DUNS: {recipient.duns ? recipient.duns : 'Not provided'}
-
-
{recipient.name || recipient.recipient_name}
-
{levelMapping[recipient.recipient_level]}
+ {isLoading ? loadingIndicator :
+
+
+ { recipients.toSorted((a, b) => (a.name?.toUpperCase() < b.name?.toUpperCase() ? -1 : 1)).map((recipient) => (
+
+
UEI: {recipient.uei ? recipient.uei : 'Not provided'})}
+ value={{
+ name: recipient.name ? recipient.name : recipient.recipient_name,
+ uei: recipient.uei,
+ duns: recipient.duns ? recipient.duns : null
+ }}
+ key={recipient.uei}
+ toggleCheckboxType={toggleRecipient}
+ selectedCheckboxes={selectedRecipients} />
+
+
Legacy DUNS: {recipient.duns ? recipient.duns : 'Not provided'}
+
+ {recipient.name || recipient.recipient_name}
+ {levelMapping[recipient.recipient_level]}
+
-
- ))}
-
-
+ ))}
+
+
}
>
);
};
diff --git a/src/js/components/search/filters/timePeriod/DateRange.jsx b/src/js/components/search/filters/timePeriod/DateRange.jsx
index 37dc130519..a677f46aa2 100644
--- a/src/js/components/search/filters/timePeriod/DateRange.jsx
+++ b/src/js/components/search/filters/timePeriod/DateRange.jsx
@@ -45,7 +45,7 @@ const DateRange = (props) => {
const [dropdownOptionSelected, setDropdownOptionSelected] = useState(false);
const [noDates, setNoDates] = useState(false);
const prevProps = usePrevious(props);
-
+ const labelArray = [];
const onClick = (e) => {
setSelectedDropdownOption(e);
@@ -71,10 +71,12 @@ const DateRange = (props) => {
}
};
- const localRemoveDateRange = () => {
- setSelectedDropdownOption('select');
- setDropdownOptionSelected(false);
- props.removeDateRange();
+ const localRemoveDateRange = (e) => {
+ if (e.type === 'click' || e.key === "Enter") {
+ setSelectedDropdownOption('select');
+ setDropdownOptionSelected(false);
+ props.removeDateRange(e);
+ }
};
const dropdownOptions = [
@@ -206,35 +208,6 @@ const DateRange = (props) => {
const startDateDisabledDays = generateStartDateDisabledDays(earliestDate);
const endDateDisabledDays = generateEndDateDisabledDays(earliestDate);
- const lastInTimePeriod = props.timePeriod[props.timePeriod.length - 1];
-
- let dateLabel = '';
- let hideTags = 'hide';
-
- if (props.timePeriod.length > 0) {
- hideTags = '';
- let start = null;
- let end = null;
-
- if (lastInTimePeriod.start_date) {
- start = dayjs(lastInTimePeriod.start_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
- }
- if (lastInTimePeriod.end_date) {
- end = dayjs(lastInTimePeriod.end_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
- }
- if (start && end) {
- dateLabel = `${start} to ${end}`;
- }
- else if (start) {
- dateLabel = `${start} to present`;
- }
- else if (end) {
- dateLabel = `... to ${end}`;
- }
- else {
- hideTags = 'hide';
- }
- }
const testDates = () => {
if (props.startDate === null && props.endDate === null) {
@@ -294,6 +267,34 @@ const DateRange = (props) => {
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [props.errorState, noDates, props.startDate, props.endDate]);
+ if (props.timePeriod?.size > 0) {
+ for (const timeinput of props.timePeriod) {
+ let dateLabel = '';
+ let start = null;
+ let end = null;
+
+ if (timeinput.start_date) {
+ start = dayjs(timeinput.start_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
+ }
+ if (timeinput.end_date) {
+ end = dayjs(timeinput.end_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
+ }
+
+ if (start && end) {
+ dateLabel = `${start} to ${end}`;
+ }
+ else if (start) {
+ dateLabel = `${start} to present`;
+ }
+ else if (end) {
+ dateLabel = `... to ${end}`;
+ }
+
+ if (dateLabel !== '') {
+ labelArray.push(dateLabel);
+ }
+ }
+ }
return (
-
+ {labelArray.map((dateLabel, index) =>
+ (
+
+ )
+ )}
+
);
diff --git a/src/js/components/search/filters/timePeriod/TimePeriod.jsx b/src/js/components/search/filters/timePeriod/TimePeriod.jsx
index 8cc7df6df4..6587506f56 100644
--- a/src/js/components/search/filters/timePeriod/TimePeriod.jsx
+++ b/src/js/components/search/filters/timePeriod/TimePeriod.jsx
@@ -36,6 +36,7 @@ const propTypes = {
timePeriods: PropTypes.array,
activeTab: PropTypes.string,
updateFilter: PropTypes.func,
+ removeFilter: PropTypes.func,
updateNewAwardsOnlySelected: PropTypes.func,
updateNewAwardsOnlyActive: PropTypes.func,
updateNaoActiveFromFyOrDateRange: PropTypes.func,
@@ -98,8 +99,8 @@ export default class TimePeriod extends React.Component {
determineIfNaoIsActive(prevProps, prevState) {
if (prevProps.filterTimePeriodFY !== this.props.filterTimePeriodFY) {
- this.props.updateNewAwardsOnlyActive(!!this.props.filterTimePeriodFY.size);
- this.props.updateNaoActiveFromFyOrDateRange(!!this.props.filterTimePeriodFY.size);
+ this.props.updateNewAwardsOnlyActive(!!this.props.filterTimePeriodFY?.size);
+ this.props.updateNaoActiveFromFyOrDateRange(!!this.props.filterTimePeriodFY?.size);
}
if (this.props.dirtyFilters) {
this.props.updateNewAwardsOnlyActive(true);
@@ -123,12 +124,10 @@ export default class TimePeriod extends React.Component {
// not filtering by a date range
return;
}
-
// prepopulate the date pickers with the current filter values (in the event of remounting
// or loading from a URL)
- const startDate = dayjs(this.props.filterTimePeriodStart, 'YYYY-MM-DD');
- const endDate = dayjs(this.props.filterTimePeriodEnd, 'YYYY-MM-DD');
-
+ const startDate = dayjs(null, 'YYYY-MM-DD');
+ const endDate = dayjs(null, 'YYYY-MM-DD');
if (startDate.isValid() && endDate.isValid()) {
this.setState({
startDateUI: startDate,
@@ -191,7 +190,7 @@ export default class TimePeriod extends React.Component {
});
}
- removeDateRange() {
+ removeDateRange(e) {
this.clearHint(true);
this.props.updateFilter({
dateType: 'dr',
@@ -203,6 +202,16 @@ export default class TimePeriod extends React.Component {
startDateUI: null,
endDateUI: null
});
+
+ if (this.props.activeTab === 'dr') {
+ this.props.updateFilter({
+ dateType: 'dr',
+ startDate: null,
+ endDate: null,
+ event: e,
+ removeFilter: true
+ });
+ }
}
showError(error, message) {
diff --git a/src/js/components/search/newResultsView/ResultsView.jsx b/src/js/components/search/newResultsView/ResultsView.jsx
index 74d9337823..86883074ed 100644
--- a/src/js/components/search/newResultsView/ResultsView.jsx
+++ b/src/js/components/search/newResultsView/ResultsView.jsx
@@ -92,7 +92,6 @@ const ResultsView = (props) => {
setResultContent(content);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.noFiltersApplied, hasResults, subaward, waitForCheckForData]);
-
return (
diff --git a/src/js/components/search/topFilterBar/TopFilterBar.jsx b/src/js/components/search/topFilterBar/TopFilterBar.jsx
index 2575b74e44..e947a219a8 100644
--- a/src/js/components/search/topFilterBar/TopFilterBar.jsx
+++ b/src/js/components/search/topFilterBar/TopFilterBar.jsx
@@ -35,7 +35,6 @@ const TopFilterBar = (props) => {
filterBarHeader += 's';
}
filterBarHeader += ':';
-
const dispatch = useDispatch();
return (
diff --git a/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx b/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx
index 696929a1a3..b524bdb1f5 100644
--- a/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx
+++ b/src/js/components/search/topFilterBar/filterGroups/BaseTopFilterGroup.jsx
@@ -24,7 +24,7 @@ export default class BaseTopFilterGroup extends React.Component {
render() {
const tags = this.props.tags.map((tag) => (
{
+ tags.push({
+ value: 'dr',
+ title: value,
+ id: uniqueId()
+ });
+ });
return tags;
}
render() {
const tags = this.generateTags();
-
return ( {
};
}
- const timePeriodFilter = {
- timePeriodStart: params.filters.time_period[0].start_date,
- timePeriodEnd: params.filters.time_period[0].end_date,
- timePeriodType: 'dr'
- };
+ const timePeriodFilter = [{ start_date: params.filters.time_period[0].start_date, end_date: params.filters.time_period[0].end_date }];
const filterValue = {
filters: {
...defaultFilters,
...categoryFilter,
...locationFilter,
- ...timePeriodFilter,
+ timePeriodType: 'dr',
+ time_period: timePeriodFilter,
...awardTypeFilter
},
version: REQUEST_VERSION
diff --git a/src/js/components/state/StateContent.jsx b/src/js/components/state/StateContent.jsx
index 9ca0a99c46..c02fa10f31 100644
--- a/src/js/components/state/StateContent.jsx
+++ b/src/js/components/state/StateContent.jsx
@@ -5,6 +5,8 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { FlexGridCol, FlexGridRow } from "data-transparency-ui";
+
import StateTimeVisualizationSectionContainer from 'containers/state/StateTimeVisualizationSectionContainer';
import TopFiveSection from './topFive/TopFiveSection';
import StateOverview from './overview/StateOverview';
@@ -16,16 +18,16 @@ const propTypes = {
};
const StateContent = ({ stateProfile }) => (
-
+
+
);
StateContent.propTypes = propTypes;
diff --git a/src/js/containers/search/SearchContainer.jsx b/src/js/containers/search/SearchContainer.jsx
index e686cdd447..662fd7dc3c 100644
--- a/src/js/containers/search/SearchContainer.jsx
+++ b/src/js/containers/search/SearchContainer.jsx
@@ -155,7 +155,7 @@ const SearchContainer = ({ history }) => {
// eslint-disable-next-line no-console
console.error('Error fetching filters from hash: ', err);
// remove hash since corresponding filter selections aren't retrievable.
- history.push('/search');
+ history?.push('/search');
request.current = null;
}
});
diff --git a/src/js/containers/search/SearchSidebarSubmitContainer.jsx b/src/js/containers/search/SearchSidebarSubmitContainer.jsx
index 3947bbfdad..7076ba8c80 100644
--- a/src/js/containers/search/SearchSidebarSubmitContainer.jsx
+++ b/src/js/containers/search/SearchSidebarSubmitContainer.jsx
@@ -3,7 +3,7 @@
* Created by Kevin Li 12/21/17
*/
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
@@ -18,6 +18,7 @@ import {
sendAnalyticEvents,
sendFieldCombinations
} from './helpers/searchAnalytics';
+import { usePrevious } from "../../helpers";
const combinedActions = Object.assign(
{},
@@ -38,90 +39,77 @@ const propTypes = {
resetAppliedFilters: PropTypes.func
};
-export class SearchSidebarSubmitContainer extends React.Component {
- constructor(props) {
- super(props);
+const SearchSidebarSubmitContainer = (props) => {
+ const [filtersChanged, setFiltersChanged] = useState(false);
+ const prevProps = usePrevious(props);
- this.state = {
- filtersChanged: false
- };
+ const areStagedFiltersEmpty = () => areFiltersEqual(props.stagedFilters, initialState);
- this.resetFilters = this.resetFilters.bind(this);
- this.applyStagedFilters = this.applyStagedFilters.bind(this);
- }
-
- componentDidUpdate(prevProps) {
- const areStagedAndAppliedFiltersEquivalent = (
- areFiltersEqual(this.props.stagedFilters, prevProps.stagedFilters) &&
- areFiltersEqual(this.props.appliedFilters, prevProps.appliedFilters)
- );
- if (!areStagedAndAppliedFiltersEquivalent) {
- this.stagingChanged();
- }
- }
-
- areStagedFiltersEmpty = () => areFiltersEqual(this.props.stagedFilters, initialState);
-
- compareStores() {
+ const compareStores = () => {
// we need to do a deep equality check by comparing every store key
- const storeKeys = Object.keys(this.props.stagedFilters);
- if (storeKeys.length !== Object.keys(this.props.appliedFilters).length) {
+ const storeKeys = Object.keys(props.stagedFilters);
+ if (storeKeys.length !== Object.keys(props.appliedFilters).length) {
// key lengths do not match, there's a difference so fail immediately
return false;
}
- return areFiltersEqual(this.props.stagedFilters, this.props.appliedFilters);
- }
+ return areFiltersEqual(props.stagedFilters, props.appliedFilters);
+ };
+
+ const resetFilters = () => {
+ props.clearStagedFilters();
+ props.resetAppliedFilters();
+ props.resetMapLegendToggle();
+ };
- stagingChanged() {
+ const stagingChanged = () => {
// do a deep equality check between the staged filters and applied filters
- if (!this.compareStores()) {
- this.setState({
- filtersChanged: true
- });
+ if (!compareStores()) {
+ setFiltersChanged(true);
}
- else if (this.state.filtersChanged) {
- this.setState({
- filtersChanged: false
- });
+ else if (filtersChanged) {
+ setFiltersChanged(false);
}
- }
+ };
- applyStagedFilters() {
- this.props.setAppliedFilterCompletion(false);
+ const applyStagedFilters = () => {
+ props.setAppliedFilterCompletion(false);
- if (areFiltersEqual(this.props.stagedFilters)) {
- this.resetFilters();
+ if (areFiltersEqual(props.stagedFilters)) {
+ resetFilters();
}
else {
- this.props.applyStagedFilters(this.props.stagedFilters);
- this.props.setAppliedFilterCompletion(true);
+ props.applyStagedFilters(props.stagedFilters);
+ props.setAppliedFilterCompletion(true);
}
- this.setState({
- filtersChanged: false
- });
+ setFiltersChanged(false);
- const events = convertFiltersToAnalyticEvents(this.props.stagedFilters);
+ const events = convertFiltersToAnalyticEvents(props.stagedFilters);
sendAnalyticEvents(events);
sendFieldCombinations(events);
- }
-
- resetFilters() {
- this.props.clearStagedFilters();
- this.props.resetAppliedFilters();
- this.props.resetMapLegendToggle();
- }
-
- render() {
- return (
-
+ };
+
+ useEffect(() => {
+ const areStagedAndAppliedFiltersEquivalent = (
+ areFiltersEqual(props.stagedFilters, prevProps?.stagedFilters) &&
+ areFiltersEqual(props.appliedFilters, prevProps?.appliedFilters)
);
- }
-}
+ if (!areStagedAndAppliedFiltersEquivalent) {
+ stagingChanged();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [props.stagedFilters, props.appliedFilters]);
+
+ return (
+
+ );
+};
+
+SearchSidebarSubmitContainer.propTypes = propTypes;
export default connect(
(state) => ({
@@ -139,4 +127,3 @@ export default connect(
})
)(SearchSidebarSubmitContainer);
-SearchSidebarSubmitContainer.propTypes = propTypes;
diff --git a/src/js/containers/search/filters/TimePeriodContainer.jsx b/src/js/containers/search/filters/TimePeriodContainer.jsx
index 60ff6cac1f..e4db061bd0 100644
--- a/src/js/containers/search/filters/TimePeriodContainer.jsx
+++ b/src/js/containers/search/filters/TimePeriodContainer.jsx
@@ -18,8 +18,8 @@ import TimePeriod from 'components/search/filters/timePeriod/TimePeriod';
export const startYear = FiscalYearHelper.earliestFiscalYear;
const propTypes = {
- updateTimePeriod: PropTypes.func,
updateTimePeriodArray: PropTypes.func,
+ setTimePeriodArray: PropTypes.func,
filterTimePeriodType: PropTypes.string,
filterTimePeriodFY: PropTypes.instanceOf(Set),
filterTimePeriodStart: PropTypes.string,
@@ -61,33 +61,32 @@ const TimePeriodContainer = (props) => {
if (activeTab === 'fy') {
newFilters.dateType = 'fy';
- // reset the date range values
- newFilters.startDate = null;
- newFilters.endDate = null;
+ props.updateTimePeriod(newFilters);
}
else {
// reset the fiscal year set
// start and end dates and datetype are in params
newFilters.fy = [];
+ props.updateTimePeriodArray(newFilters);
}
+ };
- props.updateTimePeriod(newFilters);
-
- // here is where the time_period array gets updated
- props.updateTimePeriodArray(newFilters);
+ const removeFilter = (toRemove) => {
+ if (toRemove.target) {
+ const indexToRemove = toRemove.target.getAttribute('index');
+ const timePeriodArray = props.filterTime_Period.toArray();
+ timePeriodArray.splice(indexToRemove, 1);
+ props.setTimePeriodArray(timePeriodArray);
+ }
};
const dirtyFilters = () => {
const appliedFields = [
'timePeriodFY',
- 'timePeriodStart',
- 'timePeriodEnd',
'time_period'
];
const activeFields = [
'filterTimePeriodFY',
- 'filterTimePeriodStart',
- 'filterTimePeriodEnd',
'filterTime_Period'
];
@@ -142,6 +141,7 @@ const TimePeriodContainer = (props) => {
activeTab={activeTab}
timePeriods={timePeriods}
updateFilter={updateFilter}
+ removeFilter={removeFilter}
changeTab={changeTab} />
);
};
@@ -152,9 +152,7 @@ export default connect(
(state) => ({
filterTimePeriodType: state.filters.timePeriodType,
filterTimePeriodFY: state.filters.timePeriodFY,
- filterTimePeriodStart: state.filters.timePeriodStart,
filterTime_Period: state.filters.time_period,
- filterTimePeriodEnd: state.filters.timePeriodEnd,
newAwardsOnlySelected: state.filters.filterNewAwardsOnlySelected,
newAwardsOnlyActive: state.filters.filterNewAwardsOnlyActive,
naoActiveFromFyOrDateRange: state.filters.filterNaoActiveFromFyOrDateRange,
diff --git a/src/js/containers/search/filters/programSource/TASCheckboxTreeContainer.jsx b/src/js/containers/search/filters/programSource/TASCheckboxTreeContainer.jsx
index dcb7c2c019..c26cb79dc5 100644
--- a/src/js/containers/search/filters/programSource/TASCheckboxTreeContainer.jsx
+++ b/src/js/containers/search/filters/programSource/TASCheckboxTreeContainer.jsx
@@ -59,7 +59,12 @@ const propTypes = {
nodes: PropTypes.arrayOf(PropTypes.object),
searchExpanded: PropTypes.arrayOf(PropTypes.string),
counts: PropTypes.arrayOf(PropTypes.shape({})),
- filters: PropTypes.object
+ filters: PropTypes.object,
+ showInfo: PropTypes.bool
+};
+
+const defaultProps = {
+ showInfo: true
};
const SearchNote = () => (
@@ -374,7 +379,8 @@ export class TASCheckboxTree extends React.Component {
checked,
expanded,
counts,
- searchExpanded
+ searchExpanded,
+ showInfo
} = this.props;
const {
isLoading,
@@ -386,12 +392,13 @@ export class TASCheckboxTree extends React.Component {
} = this.state;
return (
+ {showInfo &&
Search by Agency, Federal Account, or Treasury Account
}
heading="Find a Treasury Account" />
-
+ }
({
nodes: state.tas.tas.toJS(),
diff --git a/src/js/containers/search/filters/recipient/RecipientTypeContainer.jsx b/src/js/containers/search/filters/recipient/RecipientTypeContainer.jsx
index 2c814b2ec6..f565a280f0 100644
--- a/src/js/containers/search/filters/recipient/RecipientTypeContainer.jsx
+++ b/src/js/containers/search/filters/recipient/RecipientTypeContainer.jsx
@@ -17,7 +17,9 @@ const propTypes = {
appliedType: PropTypes.object
};
-const RecipientTypeContainer = (props) => {
+const RecipientTypeContainer = ({
+ toggleRecipientType, recipientType, appliedType
+}) => {
let justMounted = true;
const firstUpdate = useRef(true);
@@ -29,12 +31,12 @@ const RecipientTypeContainer = (props) => {
justMounted = false;
}, []);
- const toggleRecipientType = (selection) => {
- props.toggleRecipientType(selection);
+ const toggleRecipientTypeFunc = (selection) => {
+ toggleRecipientType(selection);
};
const dirtyFilters = () => {
- if (justMounted || is(props.recipientType, props.appliedType)) {
+ if (justMounted || is(recipientType, appliedType)) {
return null;
}
return Symbol('dirty recipient type');
@@ -43,8 +45,8 @@ const RecipientTypeContainer = (props) => {
return (
+ selectedTypes={recipientType}
+ toggleCheckboxType={toggleRecipientTypeFunc} />
);
};
diff --git a/src/js/containers/search/helpers/searchAnalytics.js b/src/js/containers/search/helpers/searchAnalytics.js
index 3c980c8511..53b846fbcf 100644
--- a/src/js/containers/search/helpers/searchAnalytics.js
+++ b/src/js/containers/search/helpers/searchAnalytics.js
@@ -234,7 +234,7 @@ export const unifyDateFields = (redux) => {
clonedRedux.timePeriod = clonedRedux.timePeriodFY;
}
else {
- clonedRedux.timePeriod = [clonedRedux.timePeriodStart, clonedRedux.timePeriodEnd];
+ clonedRedux.timePeriod = clonedRedux.time_period;
}
return clonedRedux;
};
diff --git a/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx b/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx
index 30fcdb1a0c..d35ca24758 100644
--- a/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx
+++ b/src/js/containers/search/topFilterBar/TopFilterBarContainer.jsx
@@ -65,7 +65,9 @@ const TopFilterBarContainer = (props) => {
*/
const prepareTimeFilter = () => {
let selected = false;
- const filter = {};
+ const filter = {
+ values: []
+ };
if (props.filters?.timePeriodType === 'fy') {
// check to see if any FYs are selected
if (props.filters.timePeriodFY?.size > 0) {
@@ -79,26 +81,33 @@ const TopFilterBarContainer = (props) => {
}
}
else if (props.filters?.timePeriodType === 'dr') {
- const lastInTimePeriod = props.filters.time_period[props.filters.time_period.length - 1];
- // check to see if any date ranges are selected
- if (lastInTimePeriod?.start_date || lastInTimePeriod?.end_date) {
+ // const lastInTimePeriod = props.filters.time_period[props.filters.time_period.length - 1];
+ // // check to see if any date ranges are selected
+ if (props.filters.time_period.size > 0) {
// start and end dates are provided
selected = true;
filter.code = 'timePeriodDR';
filter.name = 'Time Period';
-
- const startString = dayjs(lastInTimePeriod.start_date, 'YYYY-MM-DD')
- .format('MM/DD/YYYY');
- const endString = dayjs(lastInTimePeriod.end_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
- filter.values = [`${startString} to ${endString}`];
-
- if (!lastInTimePeriod.start_date) {
- // open-ended start date
- filter.values = [`... to ${endString}`];
- }
- else if (!lastInTimePeriod.end_date) {
- // open-ended end date
- filter.values = [`${startString} to present`];
+ for (const period of props.filters.time_period) {
+ let startString;
+ let endString;
+
+ if (period.start_date) {
+ startString = dayjs(period.start_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
+ }
+
+ if (period.end_date) {
+ endString = dayjs(period.end_date, 'YYYY-MM-DD').format('MM/DD/YYYY');
+ }
+ if (period.start_date && period.end_date) {
+ filter.values.push([`${startString} to ${endString}`]);
+ } else if (period.start_date) {
+ // open-ended end date
+ filter.values.push([`${startString} to present`]);
+ } else if (period.end_date) {
+ // open-ended start date
+ filter.values.push([`... to ${endString}`]);
+ }
}
}
}
diff --git a/src/js/dataMapping/search/newSearchFilterCategories.jsx b/src/js/dataMapping/search/newSearchFilterCategories.jsx
deleted file mode 100644
index 8a73bde669..0000000000
--- a/src/js/dataMapping/search/newSearchFilterCategories.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * SearchFilterCategories.jsx
- * Created by Andrea Blackwell November 4, 2024
- */
-
-import React from 'react';
-import { LocationSectionContainer } from "../../containers/search/filters/location/LocationSectionContainer";
-
-export const SearchFilterCategories = [
- {
- categoryKey: 'location',
- iconName: 'map-marked-alt',
- iconColor: '#34a37e',
- iconBackgroundColor: '#dbf6ed',
- title: 'Location',
- description: 'Find awards by recipient location or where work is being done'
- },
- {
- categoryKey: 'timePeriod',
- iconName: 'calendar-alt',
- iconColor: '#1A4480',
- iconBackgroundColor: '#edf5ff',
- title: 'Time Period',
- description: 'Find awards by specific date or date range'
- },
- {
- categoryKey: 'characteristics',
- iconName: 'cubes',
- iconColor: '#ff580a',
- iconBackgroundColor: '#fff3ea',
- title: 'Characteristics',
- description: 'Find awards by award type, ID, industry code, and more'
- },
- {
- categoryKey: 'recipients',
- iconName: 'building',
- iconColor: '#1b2b85',
- iconBackgroundColor: '#edf0ff',
- title: 'Recipients',
- description: 'Find awards by business, nonprofit, other organization, and more'
- },
- {
- categoryKey: 'sources',
- iconName: 'university',
- iconColor: '#009ec1',
- iconBackgroundColor: '#e5faff',
- title: 'Sources',
- description: 'Find awards by the source of funding (agency, Treasury Account Symbol, or Disaster Emergency Fund Code)'
- }
-];
-
-export const FilterCategoryTree = {
- location: {
- title: 'Location',
- component:
- },
- timePeriod: {
- title: 'Time Period',
- component: null
- },
- characteristics: {
- children: [
- {
- title: 'Award Description'
- },
- {
- title: 'Award ID'
- },
- {
- title: 'Spending Amount'
- },
- {
- title: 'Contract Award Type'
- },
- {
- title: 'North American Industry Classification System (NAICS)'
- },
- {
- title: 'Product and Service Code (PSC)'
- },
- {
- title: 'Type of Contract Pricing'
- },
- {
- title: 'Type of Set Aside'
- },
- {
- title: 'Extent Competed'
- },
- {
- title: 'Financial Assistance Award Type'
- }
-
- ]
-
- },
- recipient: {
- children: [
- {
- title: 'Recipient'
- },
- {
- title: 'Recipient Type'
- }
- ]
- },
- sources: {
- children: [
- {
- title: 'Agency'
- },
- {
- title: 'Treasury Account Symbol (TAS)'
- },
- {
- title: 'COVID-19 Spending'
- },
- {
- title: 'Infrastructure Spending'
- }
- ]
- }
-};
diff --git a/src/js/dataMapping/search/searchFilterCategories.jsx b/src/js/dataMapping/search/searchFilterCategories.jsx
new file mode 100644
index 0000000000..655ec7b9eb
--- /dev/null
+++ b/src/js/dataMapping/search/searchFilterCategories.jsx
@@ -0,0 +1,161 @@
+/**
+ * SearchFilterCategories.jsx
+ * Created by Andrea Blackwell November 4, 2024
+ */
+
+import React from 'react';
+import { LocationSectionContainer } from "../../containers/search/filters/location/LocationSectionContainer";
+import TimePeriodContainer from "../../containers/search/filters/TimePeriodContainer";
+import AwardIDSearchContainer from "../../containers/search/filters/awardID/AwardIDSearchContainer";
+import AgencyContainer from "../../containers/search/filters/AgencyContainer";
+import TASCheckboxTreeContainer from "../../containers/search/filters/programSource/TASCheckboxTreeContainer";
+import RecipientSearchContainer from "../../containers/search/filters/recipient/RecipientSearchContainer";
+import RecipientTypeContainer from "../../containers/search/filters/recipient/RecipientTypeContainer";
+
+export const SearchFilterCategories = [
+ {
+ categoryKey: 'location',
+ iconName: 'map-marked-alt',
+ iconColor: '#34a37e',
+ iconBackgroundColor: '#dbf6ed',
+ title: 'Location',
+ description: 'Find awards by recipient location or where work is being done'
+ },
+ {
+ categoryKey: 'timePeriod',
+ iconName: 'calendar-alt',
+ iconColor: '#1A4480',
+ iconBackgroundColor: '#edf5ff',
+ title: 'Time Period',
+ description: 'Find awards by specific date or date range'
+ },
+ {
+ categoryKey: 'characteristics',
+ iconName: 'cubes',
+ iconColor: '#ff580a',
+ iconBackgroundColor: '#fff3ea',
+ title: 'Characteristics',
+ description: 'Find awards by award type, ID, industry code, and more'
+ },
+ {
+ categoryKey: 'recipients',
+ iconName: 'building',
+ iconColor: '#1b2b85',
+ iconBackgroundColor: '#edf0ff',
+ title: 'Recipients',
+ description: 'Find awards by business, nonprofit, other organization, and more'
+ },
+ {
+ categoryKey: 'sources',
+ iconName: 'university',
+ iconColor: '#009ec1',
+ iconBackgroundColor: '#e5faff',
+ title: 'Sources',
+ description: 'Find awards by the source of funding (agency, Treasury Account Symbol, or Disaster Emergency Fund Code)'
+ }
+];
+
+export const FilterCategoryTree = {
+ location: {
+ title: 'Location',
+ component:
+ },
+ timePeriod: {
+ title: 'Time Period',
+ component:
+ },
+ characteristics: {
+ children: [
+ {
+ categoryType: 'ALL',
+ categories: [
+ {
+ title: 'Award Description'
+ },
+ {
+ title: 'Award ID',
+ component:
+ },
+ {
+ title: 'Spending Amount'
+ }
+ ]
+ },
+ {
+ categoryType: 'CONTRACTS',
+ categories: [
+ {
+ title: 'Contract Award Type'
+ },
+ {
+ title: 'North American Industry Classification System (NAICS)'
+ },
+ {
+ title: 'Product and Service Code (PSC)'
+ },
+ {
+ title: 'Type of Contract Pricing'
+ },
+ {
+ title: 'Type of Set Aside'
+ },
+ {
+ title: 'Extent Competed'
+ }
+ ]
+ },
+ {
+ categoryType: 'FINANCIAL ASSISTANCE',
+ categories: [
+ {
+ title: 'Financial Assistance Award Type'
+ },
+ {
+ title: 'Assistance Listing'
+ }
+ ]
+ }
+ ]
+
+ },
+ recipients: {
+ children: [
+ {
+ title: 'Recipient',
+ component:
+ },
+ {
+ title: 'Recipient Type',
+ component:
+ }
+ ]
+ },
+ sources: {
+ children: [
+ {
+ categoryType: 'doNotDisplay',
+ categories: [
+ {
+ title: 'Agency',
+ component:
+ },
+ {
+ title: 'Treasury Account Symbol (TAS)',
+ component:
+ }
+ ]
+ },
+ {
+ categoryType: 'DISASTER EMERGENCY FUND CODE (DEFC)',
+ categories: [
+ {
+ title: 'COVID-19 Spending'
+ },
+ {
+ title: 'Infrastructure Spending'
+ }
+ ]
+ }
+ ]
+ }
+};
diff --git a/src/js/helpers/searchHelper.js b/src/js/helpers/searchHelper.js
index 0e439f8d1e..aae7b03903 100644
--- a/src/js/helpers/searchHelper.js
+++ b/src/js/helpers/searchHelper.js
@@ -82,9 +82,10 @@ export const fetchAwardV2 = (awardId) => apiRequest({
url: `v2/awards/${awardId}/`
});
-export const fetchRecipients = () => apiRequest({
+export const fetchRecipients = (req) => apiRequest({
url: 'v2/recipient/',
- method: 'post'
+ method: 'post',
+ data: req
});
// Recipient search for autocomplete
@@ -180,10 +181,8 @@ export const areFiltersEqual = (filters = initialState, filterReference = initia
if (referenceObject.timePeriodType === 'fy') {
// if the time period is fiscal year, we don't care about the date range values, even
// if they're provided because the date range tab isn't selected
- delete comparisonObject.timePeriodStart;
- delete comparisonObject.timePeriodEnd;
- delete referenceObject.timePeriodStart;
- delete referenceObject.timePeriodEnd;
+ delete comparisonObject.time_period;
+ delete referenceObject.time_period;
}
else if (referenceObject.timePeriodEnd === 'dr') {
// if the time period is date range, we don't care about the fiscal year values, even
diff --git a/src/js/models/v1/search/SearchAwardsOperation.js b/src/js/models/v1/search/SearchAwardsOperation.js
index 8f34ca9826..58a58b9909 100644
--- a/src/js/models/v1/search/SearchAwardsOperation.js
+++ b/src/js/models/v1/search/SearchAwardsOperation.js
@@ -55,14 +55,10 @@ class SearchAwardsOperation {
fromState(state) {
this.keyword = state.keyword.toArray();
- this.time_period = state.time_period;
+ this.time_period = state.time_period.toArray();
this.timePeriodFY = state.timePeriodFY.toArray();
this.timePeriodRange = [];
this.timePeriodType = state.timePeriodType;
- if (state.timePeriodType === 'dr' && (state.timePeriodStart || state.timePeriodEnd)) {
- this.timePeriodRange = [state.timePeriodStart, state.timePeriodEnd];
- this.timePeriodFY = [];
- }
this.dateType = state.filterNewAwardsOnlySelected;
@@ -109,18 +105,13 @@ class SearchAwardsOperation {
}
toParams() {
- // Convert the search operation into JS objects
+ // Convert the search operation into JS objects
const filters = {};
// Add keyword
if (this.keyword?.length > 0) {
filters[rootKeys.keywords] = this.keyword;
}
- // add new time_period
- if (this.time_period?.length > 0) {
- filters[rootKeys.time_period] = this.time_period;
- }
-
// Add Time Period
if (this.timePeriodFY?.length > 0 || this.time_period?.length > 0) {
if (this.timePeriodType === 'fy' && this.timePeriodFY?.length > 0) {
@@ -134,29 +125,31 @@ class SearchAwardsOperation {
});
}
else if (this.timePeriodType === 'dr' && this.time_period?.length > 0) {
- const lastInTimePeriod = this.time_period[this.time_period?.length - 1];
-
- let start = lastInTimePeriod.start_date;
- let end = lastInTimePeriod.end_date;
-
// if no start or end date is provided, use the 2008-present date range to fill out
// the missing dates
const initialYear = FiscalYearHelper.earliestFiscalYear;
const currentYear = FiscalYearHelper.currentFiscalYear();
+ const values = [];
+ this.time_period.forEach((time) => {
+ let start = time.start_date;
+ let end = time.end_date;
- if (!start) {
- start = FiscalYearHelper.convertFYToDateRange(initialYear)[0];
- }
- if (!end) {
- end = FiscalYearHelper.convertFYToDateRange(currentYear)[1];
- }
-
- filters[rootKeys.timePeriod] = [
- {
- [timePeriodKeys.startDate]: start,
- [timePeriodKeys.endDate]: end
+ if (!start) {
+ start = FiscalYearHelper.convertFYToDateRange(initialYear)[0];
+ }
+ if (!end) {
+ end = FiscalYearHelper.convertFYToDateRange(currentYear)[1];
}
- ];
+
+ values.push(
+ {
+ [timePeriodKeys.startDate]: start,
+ [timePeriodKeys.endDate]: end
+ }
+ );
+ });
+
+ filters[rootKeys.timePeriod] = values;
}
}
diff --git a/src/js/redux/actions/search/searchFilterActions.js b/src/js/redux/actions/search/searchFilterActions.js
index df47db1dc3..a829f05573 100644
--- a/src/js/redux/actions/search/searchFilterActions.js
+++ b/src/js/redux/actions/search/searchFilterActions.js
@@ -27,7 +27,9 @@ export const updateTimePeriodArray = (state) => ({
dateType: state.dateType,
fy: state.fy,
start: state.startDate,
- end: state.endDate
+ end: state.endDate,
+ removeFilter: state.removeFilter,
+ event: state.event
});
export const updateNewAwardsOnlySelected = (state) => ({
diff --git a/src/js/redux/reducers/search/filters/timePeriodFilterFunctions.js b/src/js/redux/reducers/search/filters/timePeriodFilterFunctions.js
index 760a1e2d69..2befd908cf 100644
--- a/src/js/redux/reducers/search/filters/timePeriodFilterFunctions.js
+++ b/src/js/redux/reducers/search/filters/timePeriodFilterFunctions.js
@@ -5,14 +5,26 @@
/* eslint-disable import/prefer-default-export */
// We only have one export but want to maintain consistency with other query modules
-export const updateSelectedDates = (currentDates, date) => {
- if (date.start || date.end) {
- currentDates.push({
+export const updateDRs = (currentDates, date) => {
+ let updatedSet = currentDates;
+ // remove clicked index
+ if (date.removeFilter && date.event.target.getAttribute("index")) {
+ let i = 0;
+ for (const item of updatedSet) {
+ if (i === parseInt(date.event.target.getAttribute("index"), 10)) {
+ updatedSet = currentDates.delete(item);
+ }
+ i++;
+ }
+ } else if (date.start || date.end) {
+ updatedSet = updatedSet.add({
start_date: date.start,
end_date: date.end
});
}
- return currentDates;
+ return updatedSet;
};
+
+export const setDR = (newDR) => newDR;
/* eslint-enable import/prefer-default-export */
diff --git a/src/js/redux/reducers/search/searchFiltersReducer.js b/src/js/redux/reducers/search/searchFiltersReducer.js
index 6d6ca2012f..353b54427d 100644
--- a/src/js/redux/reducers/search/searchFiltersReducer.js
+++ b/src/js/redux/reducers/search/searchFiltersReducer.js
@@ -14,7 +14,7 @@ import * as AwardAmountFilterFunctions from './filters/awardAmountFilterFunction
import * as OtherFilterFunctions from './filters/OtherFilterFunctions';
import * as ContractFilterFunctions from './filters/contractFilterFunctions';
import * as ProgramSourceFilterFunctions from './filters/programSourceFilterFunctions';
-
+import * as TimePeriodFilterFunctions from './filters/timePeriodFilterFunctions';
// update this version when changes to the reducer structure are made
// frontend will reject inbound hashed search filter sets with different versions because the
// data structures may have changed
@@ -32,6 +32,7 @@ export const requiredTypes = {
selectedFundingAgencies: OrderedMap,
selectedAwardingAgencies: OrderedMap,
selectedRecipients: Set,
+ time_period: Set,
recipientType: Set,
selectedRecipientLocations: OrderedMap,
awardType: Set,
@@ -52,9 +53,7 @@ export const initialState = {
keyword: OrderedMap(),
timePeriodType: 'dr',
timePeriodFY: Set(),
- time_period: [],
- timePeriodStart: null,
- timePeriodEnd: null,
+ time_period: Set(),
filterNewAwardsOnlySelected: false,
filterNewAwardsOnlyActive: false,
filterNaoActiveFromFyOrDateRange: false,
@@ -95,19 +94,16 @@ const searchFiltersReducer = (state = initialState, action) => {
// FY time period is stored as an ImmutableJS set
return Object.assign({}, state, {
timePeriodType: action.dateType,
- timePeriodStart: action.start,
- timePeriodEnd: action.end,
timePeriodFY: new Set(action.fy)
});
}
- // New Time Period Filter Array
+ // New Time Period Filter Item
case 'ADD_TIME_PERIOD_OBJECT': {
return Object.assign({}, state, {
- time_period: state.time_period.concat({
- start_date: action.start,
- end_date: action.end
- })
+ timePeriodType: action.dateType,
+ time_period: TimePeriodFilterFunctions.updateDRs(
+ state.time_period, action)
});
}
@@ -308,8 +304,7 @@ const searchFiltersReducer = (state = initialState, action) => {
return Object.assign({}, state, {
timePeriodType: initialState.timePeriodType,
timePeriodFY: initialState.timePeriodFY,
- timePeriodStart: initialState.timePeriodStart,
- timePeriodEnd: initialState.timePeriodEnd
+ time_period: initialState.time_period
});
}
case 'RESET_TIME_PERIOD_OBJECT': {
diff --git a/tests/containers/search/helpers/searchAnalytics-test.js b/tests/containers/search/helpers/searchAnalytics-test.js
index 474eca099d..0af9ca608f 100644
--- a/tests/containers/search/helpers/searchAnalytics-test.js
+++ b/tests/containers/search/helpers/searchAnalytics-test.js
@@ -201,11 +201,10 @@ describe('searchAnalytics', () => {
it('should set the `timePeriod` field to an array of `timePeriodStart` and `timePeriodEnd` filters when a date range is selected', () => {
const filters = {
timePeriodType: 'dr',
- timePeriodStart: '1900-01-01',
- timePeriodEnd: '1900-02-01'
+ time_period: new Set([{ start_date: '1900-01-01', end_date: '1900-02-01' }])
};
const redux = searchAnalytics.unifyDateFields(filters);
- expect(redux.timePeriod).toEqual(['1900-01-01', '1900-02-01']);
+ expect(redux.timePeriod).toEqual(new Set([{ start_date: '1900-01-01', end_date: '1900-02-01' }]));
});
});
diff --git a/tests/containers/search/mockSearchHashes.js b/tests/containers/search/mockSearchHashes.js
index b2374c7319..229888eb59 100644
--- a/tests/containers/search/mockSearchHashes.js
+++ b/tests/containers/search/mockSearchHashes.js
@@ -18,14 +18,13 @@ export const mockFilters = {
selectedLocations: {},
recipientType: [],
timePeriodFY: [`${FiscalYearHelper.currentFiscalYear()}`],
+ time_period: [],
timePeriodType: "fy",
- timePeriodStart: null,
selectedAwardingAgencies: {},
awardType: [],
recipientDomesticForeign: "all",
selectedRecipientLocations: {},
awardAmounts: {},
- timePeriodEnd: null,
selectedCFDA: {},
pricingType: [],
setAside: [],
diff --git a/tests/redux/reducers/search/searchFiltersReducer-test.js b/tests/redux/reducers/search/searchFiltersReducer-test.js
index daabeeaf65..7673ba2bdc 100644
--- a/tests/redux/reducers/search/searchFiltersReducer-test.js
+++ b/tests/redux/reducers/search/searchFiltersReducer-test.js
@@ -109,26 +109,45 @@ describe('searchFiltersReducer', () => {
const action = {
type: 'UPDATE_SEARCH_FILTER_TIME_PERIOD',
dateType: 'fy',
- fy: ['1778', '1777', '1775'],
- start: null,
- end: null
+ fy: ['1778', '1777', '1775']
};
const expected = {
timePeriodType: 'fy',
- timePeriodFY: new Set(['1778', '1777', '1775']),
- timePeriodStart: null,
- timePeriodEnd: null
+ timePeriodFY: new Set(['1778', '1777', '1775'])
};
- const updatedState = searchFiltersReducer(undefined, action);
+ const updatedState = searchFiltersReducer(null, action);
+
+ Object.keys(expected).forEach((key) => {
+ expect(updatedState[key]).toEqual(expected[key]);
+ });
+ });
+ });
+
+ describe('ADD_TIME_PERIOD_OBJECT', () => {
+ it('should set the time period value to the provided action date', () => {
+ const startingState = Object.assign({}, initialState);
+ const action = {
+ type: 'ADD_TIME_PERIOD_OBJECT',
+ dateType: 'dr',
+ start: '1776-01-01',
+ end: '1776-12-31'
+ };
+
+ const expected = {
+ timePeriodType: 'dr',
+ time_period: new Set([{ start_date: '1776-01-01', end_date: '1776-12-31' }])
+ };
+ const updatedState = searchFiltersReducer(startingState, action);
Object.keys(expected).forEach((key) => {
expect(updatedState[key]).toEqual(expected[key]);
});
});
});
+
describe('UPDATE_SEARCH_FILTER_NEW_AWARDS_ONLY_SELECTED', () => {
it('should set the filterNewAwardsOnlySelected value to the provided action data', () => {
const action = {
@@ -419,6 +438,7 @@ describe('searchFiltersReducer', () => {
describe('UPDATE_RECIPIENT_DOMESTIC_FORIEGN', () => {
it(
+ // eslint-disable-next-line no-useless-concat
'should set the Recipient domestic/foreign filter ' + 'scope to the input string',
() => {
const action = {
@@ -824,8 +844,7 @@ describe('searchFiltersReducer', () => {
type: 'UPDATE_SEARCH_FILTER_TIME_PERIOD',
dateType: 'fy',
fy: ['1778', '1777', '1775'],
- start: null,
- end: null
+ time_period: new Set()
};
const resetAction = {
@@ -834,16 +853,12 @@ describe('searchFiltersReducer', () => {
const expectedFirst = {
timePeriodType: 'fy',
- timePeriodFY: new Set(['1778', '1777', '1775']),
- timePeriodStart: null,
- timePeriodEnd: null
+ timePeriodFY: new Set(['1778', '1777', '1775'])
};
const expectedSecond = {
timePeriodType: 'dr',
- timePeriodFY: new Set(),
- timePeriodStart: null,
- timePeriodEnd: null
+ timePeriodFY: new Set()
};
// perform the first action to change the time period filter values
@@ -870,8 +885,7 @@ describe('searchFiltersReducer', () => {
type: 'UPDATE_SEARCH_FILTER_TIME_PERIOD',
dateType: 'dr',
fy: [],
- start: '1776-01-01',
- end: '1776-12-31'
+ time_period: new Set([{ start_date: '1776-01-01', end_date: '1776-12-31' }])
};
const resetAction = {
@@ -881,15 +895,13 @@ describe('searchFiltersReducer', () => {
const expectedFirst = {
timePeriodType: 'dr',
timePeriodFY: new Set(),
- timePeriodStart: '1776-01-01',
- timePeriodEnd: '1776-12-31'
+ time_period: new Set()
};
const expectedSecond = {
timePeriodType: 'dr',
timePeriodFY: new Set(),
- timePeriodStart: null,
- timePeriodEnd: null
+ time_period: new Set()
};
// perform the first action to change the time period filter values
@@ -948,17 +960,13 @@ describe('searchFiltersReducer', () => {
const secondAction = {
type: 'UPDATE_SEARCH_FILTER_TIME_PERIOD',
dateType: 'fy',
- fy: ['1778', '1777', '1775'],
- start: null,
- end: null
+ fy: ['1778', '1777', '1775']
};
const firstExpected = 'domestic';
const secondExpected = {
timePeriodType: 'fy',
- timePeriodFY: new Set(['1778', '1777', '1775']),
- timePeriodStart: null,
- timePeriodEnd: null
+ timePeriodFY: new Set(['1778', '1777', '1775'])
};
// perform the first action that updates the domestic/foreign scope
diff --git a/tests/testResources/defaultReduxFilters.js b/tests/testResources/defaultReduxFilters.js
index b32a958d58..af3d2b8697 100644
--- a/tests/testResources/defaultReduxFilters.js
+++ b/tests/testResources/defaultReduxFilters.js
@@ -14,11 +14,9 @@ import * as FiscalYearHelper from '../../src/js/helpers/fiscalYearHelper';
export const defaultFilters = {
keyword: new OrderedMap(),
awardType: new Set(),
- time_period: [],
+ time_period: new Set(),
timePeriodType: 'dr',
timePeriodFY: new Set([`${FiscalYearHelper.currentFiscalYear()}`]),
- timePeriodStart: null,
- timePeriodEnd: null,
selectedLocations: new OrderedMap(),
locationDomesticForeign: 'all',
budgetFunctions: new OrderedMap(),