From c66343930d7b94e75aeb606c0e11a652a93c7399 Mon Sep 17 00:00:00 2001
From: Eddie Maldonado
Date: Tue, 24 Jan 2023 10:45:48 -0500
Subject: [PATCH] Search panel visual changes (#1887)
* feat: styling of search input and submit button
* feat: styling of search radio buttons
* feat: horizontal separator and other misc styling
* feat: initial styling of previous searches
* feat: hover and focus for recent searches
* feat: focus and hover states for search input clear button
* feat: styling of "no search results" state
* refactor: use table for card properties list
* feat: initial pass at using universal card for search results
* fix: spacing adjustments to search panel
* fix: allow title row of card to grow to accommodate multiple lines
* feat: make card component support optional left-hand icon component
* feat: display bus icon in search results card
* fix: CSS spacing issues
* feat: drawer tab for search panel
* feat: highlight search terms in results
Also refactors Card component to use PropertiesList
* test: remove obsolete snapshot test
* fix: handle shuttles in search results
* refactor(test): remove unneeded testid for drawer tab
* feat: selecting / unselecting a result hides / shows search panel
* feat: card improvements for selected state and misc styling
* feat: give selected state to relevant card in search results
* feat: card styling updates based on new designs
* fix: address some styling glitches
* feat: updated styling of mobile view toggle button
* feat: backport CSS changes to _search_page.scss
* fix: improve ARIA handling of card selection state + tests
* fix(tests): update snapshots
* refactor: leaflet z-index constant
* refactor: make use of RouteVariantName component
* refactor: use ReactElement instead of JSX.Element
* fix: responding to review comments
* fix: add box-shadow for card
* feat: drop shadow for search panel
* feat: widen search panel
* feat: omit operator first name from search panel card
* fix: correct background colors for card selected states
* feat: hide scrollbar on search panel when collapsed
---
assets/css/_card.scss | 101 +-
assets/css/_leaflet.scss | 3 +
assets/css/_map_page.scss | 74 +-
assets/css/_recent_searches.scss | 20 +-
assets/css/_search_form.scss | 77 +-
assets/css/_search_page.scss | 85 +-
assets/css/_search_results.scss | 95 +-
assets/css/_skate_ui.scss | 65 ++
assets/css/_ui_kit.scss | 17 -
.../_vehicle_properties_panel.scss | 3 +-
assets/src/components/card.tsx | 56 +-
assets/src/components/drawerTab.tsx | 2 +-
assets/src/components/mapPage.tsx | 17 +-
assets/src/components/propertiesList.tsx | 16 +-
assets/src/components/recentSearches.tsx | 27 +-
assets/src/components/searchForm.tsx | 4 +-
assets/src/components/searchResults.tsx | 91 +-
assets/src/components/vehicleRouteSummary.tsx | 2 +-
.../__snapshots__/app.test.tsx.snap | 2 +-
.../appStateWrapper.test.tsx.snap | 2 +-
.../__snapshots__/drawerTab.test.tsx.snap | 4 +-
.../__snapshots__/ladderPage.test.tsx.snap | 8 +-
.../__snapshots__/mapPage.test.tsx.snap | 84 +-
.../notificationDrawer.test.tsx.snap | 86 +-
.../recentSearches.test.tsx.snap | 45 +-
.../__snapshots__/searchForm.test.tsx.snap | 10 +-
.../__snapshots__/searchPage.test.tsx.snap | 22 +-
.../__snapshots__/searchResults.test.tsx.snap | 945 +++++++++++-------
.../shuttleMapPage.test.tsx.snap | 10 +-
.../__snapshots__/shuttlePicker.test.tsx.snap | 6 +-
assets/tests/components/card.test.tsx | 66 +-
assets/tests/components/mapPage.test.tsx | 28 +-
.../tests/components/pickerContainer.test.tsx | 2 +-
.../tests/components/propertiesList.test.tsx | 21 +
.../tests/components/searchResults.test.tsx | 96 +-
.../shuttlePickerContainer.test.tsx | 2 +-
36 files changed, 1359 insertions(+), 835 deletions(-)
diff --git a/assets/css/_card.scss b/assets/css/_card.scss
index 23cca4709..c49995e33 100644
--- a/assets/css/_card.scss
+++ b/assets/css/_card.scss
@@ -7,13 +7,7 @@
border-radius: 0.5rem;
padding: 0.3125rem 0.3125rem 1rem 1rem;
- &:hover:not(.m-card--no-focus-or-hover) {
- box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.12);
- }
-
- &:focus:not(.m-card--no-focus-or-hover) {
- box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.075);
- }
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.075);
button {
text-align: start;
@@ -22,16 +16,27 @@
}
.m-card__left {
- display: flex;
- flex-direction: column;
flex-grow: 1;
position: relative;
+ display: grid;
+ grid-template-areas: "icon main-contents";
+ grid-template-columns: min-content 1fr;
&:last-child {
padding-right: 0.3125rem;
}
}
+.m-card__icon {
+ grid-area: icon;
+}
+
+.m-card__left-content {
+ display: flex;
+ flex-direction: column;
+ grid-area: main-contents;
+}
+
.m-card__right {
min-width: 2.5rem;
@@ -50,7 +55,7 @@
justify-content: space-between;
align-items: center;
width: 100%;
- height: 1.625rem;
+ min-height: 1.625rem;
margin-top: 0.3125rem;
}
@@ -94,16 +99,50 @@
color: $color-gray-700;
}
-.m-card__properties {
- margin-top: 1rem;
- margin-bottom: 0;
+.m-card__contents .m-properties-list {
+ padding: 0;
- li {
- font-size: 0.875rem;
- line-height: 0.875rem;
+ .m-properties-list__table {
+ &:not(:first-child) {
+ margin-top: 1rem;
+ }
- &:not(:last-child) {
- padding-bottom: 0.5rem;
+ &:first-child {
+ margin-top: 0.375rem;
+ }
+
+ margin-bottom: 0;
+
+ tr {
+ font-size: 0.875rem;
+ line-height: 0.875rem;
+ vertical-align: top;
+
+ &:not(:last-child) th,
+ td {
+ padding-bottom: 0.5rem;
+ }
+
+ td .highlighted {
+ background-color: $color-eggplant-200;
+ }
+
+ .m-properties-list__property-label {
+ color: $color-gray-700;
+ text-align: left;
+ text-transform: initial;
+ font-size: inherit;
+ }
+
+ .m-properties-list__property-value {
+ color: $color-gray-600;
+ }
+ }
+
+ .m-properties-list__property--last-login
+ .m-properties-list__property-value {
+ color: $color-gray-600;
+ font-size: inherit;
}
}
}
@@ -126,12 +165,12 @@
background-color: $color-kiwi-100;
border: 1px solid $color-kiwi-400;
- &:hover:not(.m-card--no-focus-or-hover) {
+ &:hover:not(.m-card--no-focus-or-hover):not(.m-card--selected) {
background-color: $white;
border: 1px solid $color-kiwi-300;
}
- &:focus:not(.m-card--no-focus-or-hover) {
+ &:focus-within:not(.m-card--no-focus-or-hover) {
background-color: $color-kiwi-200;
border: 2px solid $color-kiwi-400;
}
@@ -141,7 +180,7 @@
background-color: $color-gray-50;
border: 1px solid $color-gray-400;
- &:hover:not(.m-card--no-focus-or-hover) {
+ &:hover:not(.m-card--no-focus-or-hover):not(.m-card--selected) {
background-color: $color-gray-50;
border: 1px solid $color-kiwi-300;
}
@@ -156,6 +195,26 @@
&.m-card {
background-color: $white;
border: 1px solid $color-gray-400;
+
+ &:hover:not(.m-card--no-focus-or-hover):not(.m-card--selected) {
+ background-color: $color-gray-100;
+ border: 1px solid $color-gray-300;
+ }
+
+ &:focus-within:not(.m-card--no-focus-or-hover):not(.m-card--selected) {
+ background-color: $color-gray-100;
+ border: 2px solid $color-eggplant-500;
+ }
+
+ &.m-card--selected {
+ background-color: $color-eggplant-100;
+ border: 1px solid $color-eggplant-500;
+ }
+
+ &:focus-within:not(.m-card--no-focus-or-hover).m-card--selected {
+ background-color: $color-eggplant-100;
+ border: 2px solid $color-eggplant-500;
+ }
}
&.m-card__title {
diff --git a/assets/css/_leaflet.scss b/assets/css/_leaflet.scss
index f0dec753f..6f411862f 100644
--- a/assets/css/_leaflet.scss
+++ b/assets/css/_leaflet.scss
@@ -1,3 +1,6 @@
+// From here: https://github.com/Leaflet/Leaflet/blob/5c29d615563835d373a51b91fc3513a17907da96/dist/leaflet.css#L87
+$leaflet-pane-z-index: 400;
+
.leaflet-container {
width: 100%;
height: 100%;
diff --git a/assets/css/_map_page.scss b/assets/css/_map_page.scss
index 76f56f994..dc27065c3 100644
--- a/assets/css/_map_page.scss
+++ b/assets/css/_map_page.scss
@@ -1,3 +1,5 @@
+$map-page-search-panel-width: 24rem;
+
.m-map-page {
display: flex;
flex: 1 1 auto;
@@ -13,33 +15,78 @@
position: relative;
}
+.m-map-page__input {
+ padding: 0 1.5625rem;
+}
+
.m-map-page__input-and-results {
- background-color: $color-bg-base;
+ background-color: $color-gray-300;
display: flex;
flex: 0 0 auto;
flex-direction: column;
- width: 22rem;
-}
+ gap: 1rem;
+ width: $map-page-search-panel-width;
+ height: 100%;
+ box-sizing: border-box;
+ position: absolute;
+ z-index: #{$leaflet-pane-z-index + 100};
-.m-map-page__input,
-.m-search-display {
- padding: 1.5rem 1.1875rem;
+ padding: 1.25rem 0 0 0;
+
+ transition: $transition-slide;
+
+ filter: drop-shadow(2px 0px 10px rgba(0, 0, 0, 0.2));
+
+ hr {
+ height: 1px;
+ background-color: $color-gray-100;
+ border: none;
+ width: calc(100% - 2 * 1.5625rem);
+ margin: 0 1.5625rem;
+ }
+
+ &.visible {
+ left: 0;
+ }
+
+ &.hidden {
+ left: calc(-1 * #{$map-page-search-panel-width} + 1rem);
+
+ .m-search-display {
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+
+ &::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+ }
+ }
+ }
}
-.m-map-page__input {
- border-bottom: 1px solid $white;
+.m-map-page__input-and-results .c-drawer-tab {
+ left: 100%;
+ top: 0;
+ background-color: $color-gray-300;
+ z-index: #{$leaflet-pane-z-index + 100};
+
+ .c-drawer-tab__tab-button {
+ &:focus,
+ &:hover {
+ color: $color-eggplant-500;
+ }
+ }
}
.m-map-page__toggle-mobile-display-button {
- @include button-text;
display: none;
- font-size: 0.875rem;
margin: 0.5rem auto 0;
}
.m-search-display {
flex: 1 1 auto;
overflow-y: scroll;
+ padding: 0.625rem 1rem 0 1rem;
}
@media screen and (max-width: $mobile-max-width) {
@@ -47,6 +94,10 @@
flex-direction: column;
}
+ .m-map-page__input-and-results .c-drawer-tab {
+ display: none;
+ }
+
.m-map-page--show-list {
.m-map-page__input-and-results {
flex: 1 1 auto;
@@ -73,7 +124,8 @@
.m-map-page__input-and-results {
box-sizing: border-box;
- width: auto;
+ width: 100%;
+ position: relative;
}
.m-map-page__toggle-mobile-display-button {
diff --git a/assets/css/_recent_searches.scss b/assets/css/_recent_searches.scss
index a3a77e57b..8d70a67ad 100644
--- a/assets/css/_recent_searches.scss
+++ b/assets/css/_recent_searches.scss
@@ -1,15 +1,19 @@
.m-recent-searches {
- background-color: $color-bg-base;
flex: 1 1 auto;
width: 100%;
-}
-.m-recent-searches__heading {
- @include font-label;
+ ul {
+ margin-top: 0.875rem;
+ margin-bottom: 0;
+
+ li:not(:last-child) {
+ margin-bottom: 0.75rem;
+ }
+ }
}
-.m-recent-searches__button {
- @include button-text;
- display: block;
- margin-top: 1rem;
+.m-recent-searches__heading {
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-bold);
+ color: var(--font-color-on-light-800);
}
diff --git a/assets/css/_search_form.scss b/assets/css/_search_form.scss
index 4d25364e1..a33111231 100644
--- a/assets/css/_search_form.scss
+++ b/assets/css/_search_form.scss
@@ -1,5 +1,9 @@
.m-search-form__row {
display: flex;
+
+ &:not(:last-child) {
+ margin-bottom: 1rem;
+ }
}
.m-search-form__text {
@@ -9,43 +13,62 @@
.m-search-form__input {
width: 100%;
+ height: 2.375rem;
+ box-sizing: border-box;
+
+ border-radius: 4px 0 0 4px;
+ border: none;
+
+ padding: 7px 0 7px 13px;
+
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-reg);
+ color: var(--font-color-on-light-600);
+
+ &:focus {
+ border: 1px solid $color-eggplant-500;
+ }
}
.m-search-form__clear {
- @include button-transparent;
- @include button-icon(0.75rem);
- right: 0;
- padding: 0 0.375rem;
+ @include button-icon(0.875rem);
+ right: 0.75rem;
position: absolute;
- top: 0.875rem;
+ top: 0.75rem;
+
+ color: $color-gray-600;
+
+ &:hover,
+ &:focus-within {
+ color: $color-eggplant-500;
+ }
}
.m-search-form__submit {
- @include button-primary;
- @include button-icon(1.3125rem);
+ @include button-icon(1rem);
+
flex: 1 0 auto;
- margin-left: 0.5rem;
- width: 2.5rem;
- height: 2.5rem;
+ max-width: 2.625rem;
+ max-height: 2.375rem;
+
+ border-radius: 0 4px 4px 0;
+
display: flex;
+
justify-content: center;
align-items: center;
-
- &:disabled {
- @include button-disabled;
- }
}
.m-search-form__property-buttons {
display: flex;
flex: 1 0 auto;
list-style-type: none;
- margin-top: 0.75rem;
+ margin: 0;
}
.m-search-form__property-button {
flex: 1 0 0;
- margin-right: 0.3rem;
+ margin-right: 0.75rem;
&:last-child {
margin-right: 0;
@@ -57,16 +80,16 @@
}
.m-search-form__property-label {
- @include button-simple;
- display: block;
- padding-left: 0.8125rem;
- padding-right: 0.8125rem;
- text-align: center;
- text-transform: uppercase;
-
- .m-search-form__property-input:checked + & {
- @include button-primary;
- padding-left: 0.8125rem;
- padding-right: 0.8125rem;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ height: 1.5625rem;
+
+ text-transform: capitalize;
+
+ // Override base button-search-filter style by giving a more specific selector
+ &.button-search-filter {
+ font-size: var(--font-size-xs);
}
}
diff --git a/assets/css/_search_page.scss b/assets/css/_search_page.scss
index d70155410..b956b1640 100644
--- a/assets/css/_search_page.scss
+++ b/assets/css/_search_page.scss
@@ -1,3 +1,5 @@
+$search-page-search-panel-width: 22.0625rem;
+
.m-search-page {
display: flex;
flex: 1 1 auto;
@@ -7,38 +9,58 @@
overflow: visible;
}
+.m-search-page__map {
+ display: flex;
+ flex: 1 1 auto;
+ position: relative;
+}
+
+.m-search-page__input {
+ padding: 0 1.5625rem;
+}
+
.m-search-page__input-and-results {
- background-color: $color-bg-base;
+ background-color: $color-gray-300;
display: flex;
flex: 0 0 auto;
flex-direction: column;
- width: 22rem;
-}
+ gap: 1rem;
+ width: $search-page-search-panel-width;
+ height: 100%;
+ box-sizing: border-box;
+ position: absolute;
+ z-index: #{$leaflet-pane-z-index + 100};
-.m-search-page__input,
-.m-search-display {
- padding: 1.5rem 1.1875rem;
-}
+ padding: 1.25rem 0 0 0;
-.m-search-page__input {
- border-bottom: 1px solid $white;
+ transition: $transition-slide;
+
+ hr {
+ height: 1px;
+ background-color: $color-gray-100;
+ border: none;
+ width: calc(100% - 2 * 1.5625rem);
+ margin: 0 1.5625rem;
+ }
+
+ &.visible {
+ left: 0;
+ }
+
+ &.hidden {
+ left: calc(-1 * #{$search-page-search-panel-width} + 1rem);
+ }
}
.m-search-page__toggle-mobile-display-button {
- @include button-text;
display: none;
- font-size: 0.875rem;
margin: 0.5rem auto 0;
}
.m-search-display {
flex: 1 1 auto;
overflow-y: scroll;
-}
-
-.m-search-page__map {
- flex: 1 1 auto;
- position: relative;
+ padding: 0.625rem 1rem 0 1rem;
}
@media screen and (max-width: $mobile-max-width) {
@@ -46,6 +68,10 @@
flex-direction: column;
}
+ .m-search-page__input-and-results .c-drawer-tab {
+ display: none;
+ }
+
.m-search-page--show-list {
.m-search-page__input-and-results {
flex: 1 1 auto;
@@ -72,7 +98,8 @@
.m-search-page__input-and-results {
box-sizing: border-box;
- width: auto;
+ width: 100%;
+ position: relative;
}
.m-search-page__toggle-mobile-display-button {
@@ -85,3 +112,27 @@
width: 100%;
}
}
+
+$search-page-search-stub-size: 10px;
+
+.m-search-page__map .m-vehicle-properties-card {
+ position: absolute;
+ top: 0.5rem;
+ left: calc(
+ env(safe-area-inset-left) + 60px - #{$search-page-search-stub-size}
+ );
+
+ // Above the highest pane in the map (popup pane): https://leafletjs.com/reference.html#map
+ z-index: 7001;
+
+ cursor: default;
+}
+
+.m-search-page__input-and-results[hidden] + *::before {
+ content: "";
+
+ height: 100%;
+ width: $search-page-search-stub-size;
+
+ background-color: $color-gray-400;
+}
diff --git a/assets/css/_search_results.scss b/assets/css/_search_results.scss
index 1c2e45fa5..e217548ed 100644
--- a/assets/css/_search_results.scss
+++ b/assets/css/_search_results.scss
@@ -10,78 +10,61 @@
@include button-text;
}
-.m-search-results__card {
- background-color: $white;
- border-radius: 4px;
- box-shadow: $subtle-box-shadow;
- cursor: pointer;
- padding: 1rem 1rem 0.5rem;
- position: relative;
- text-align: start;
- width: 100%;
-
- li:not(:last-child) & {
+.m-search-results__none {
+ *:not(:last-child) {
margin-bottom: 1rem;
}
- &--selected,
- &:hover {
- background-color: $color-secondary-light;
-
- .highlighted {
- background-color: $color-secondary-medium;
- }
+ .m-search-results__heading {
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-bold);
+ color: $black;
}
- &--new {
- border: 1px solid $color-secondary-dark;
- box-shadow: 0 2px 4px 0 rgba(77, 182, 172, 0.3);
-
- .m-properties-list__property--last-login
- .m-properties-list__property-value {
- color: $color-secondary-dark;
- }
+ p {
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-reg);
+ color: $color-gray-700;
}
- .m-properties-list {
+ button {
+ color: $color-eggplant-700;
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-semi);
padding: 0;
- }
-}
-
-.m-search-results__card-new-badge {
- position: absolute;
- right: 1rem;
- top: 1rem;
-}
-
-.m-search-results__card-new-badge-label {
- @include font-label;
- color: $color-secondary-dark;
-}
-
-.m-search-results__card-new-badge-icon {
- display: inline-block;
- fill: $color-secondary-dark;
- margin-left: 0.3rem;
- stroke: none;
- width: 9px;
-}
+ text-decoration: none;
-.m-search-results__card-route-label {
- color: $color-font-grey;
- font-size: 0.75rem;
- margin: 0.5rem 0;
+ &:hover {
+ color: $color-eggplant-500;
+ }
- .m-route-variant-name__route-id {
- font-weight: bold;
+ &:focus {
+ color: $color-eggplant-500;
+ border: 1px solid $color-eggplant-700;
+ border-radius: 3px;
+ }
}
}
.m-search-results__list {
margin: 0;
position: relative;
+
+ & > *:not(:last-child) {
+ margin-bottom: 1rem;
+ }
}
-.m-search-results__note {
- color: $color-font-grey;
+.m-search-results__result {
+ .m-card__icon {
+ padding-right: 1rem;
+
+ svg {
+ width: 2.5rem !important;
+
+ .m-vehicle-icon__label-background {
+ fill: none;
+ }
+ }
+ }
}
diff --git a/assets/css/_skate_ui.scss b/assets/css/_skate_ui.scss
index d015b05d3..8c8d2bd8b 100644
--- a/assets/css/_skate_ui.scss
+++ b/assets/css/_skate_ui.scss
@@ -6,6 +6,7 @@ $font-colors: (
"on-light-900": $color-gray-900,
"on-light-800": $color-gray-800,
"on-light-700": $color-gray-700,
+ "on-light-600": $color-gray-600,
"on-dark": $white,
@@ -108,6 +109,70 @@ $font-weights: (
line-height: 1;
}
+/* Input Submit Button */
+
+.button-submit {
+ color: $white;
+ background-color: $color-eggplant-700;
+
+ &:hover {
+ background-color: $color-eggplant-500;
+ }
+
+ &:focus {
+ background-color: $color-eggplant-500;
+ border: 2px solid $color-eggplant-700;
+ }
+
+ &:disabled {
+ background-color: $color-gray-600;
+ }
+}
+
+/* Search Filters */
+
+.button-search-filter {
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-bold);
+ color: var(--font-color-on-light-600);
+ background-color: $color-gray-50;
+
+ border-radius: 4px;
+
+ input:checked + & {
+ color: var(--font-color-on-dark);
+ background-color: $color-eggplant-700;
+ }
+
+ &:hover {
+ color: var(--font-color-on-dark);
+ background-color: $color-eggplant-500;
+ }
+
+ &:focus {
+ color: var(--font-color-on-light-700);
+ border: 1px solid $color-eggplant-500;
+ }
+}
+
+.button-text {
+ color: $color-eggplant-700;
+ font-size: var(--font-size-s);
+ font-weight: var(--font-weight-semi);
+ padding: 0;
+ text-decoration: none;
+
+ &:hover {
+ color: $color-eggplant-500;
+ }
+
+ &:focus {
+ color: $color-eggplant-500;
+ border: 1px solid $color-eggplant-700;
+ border-radius: 3px;
+ }
+}
+
.title-case {
text-transform: capitalize;
}
diff --git a/assets/css/_ui_kit.scss b/assets/css/_ui_kit.scss
index 64a003bcf..c6506b9f1 100644
--- a/assets/css/_ui_kit.scss
+++ b/assets/css/_ui_kit.scss
@@ -366,23 +366,6 @@ select {
}
}
-input:not(.form-check-input) {
- background-color: $white;
- border: 2px solid transparent;
- border-radius: 0.5rem;
- box-sizing: border-box;
- line-height: 1rem;
- padding: 0.5rem 1rem 0.5rem 0.8125rem;
-
- &:hover {
- border: 2px solid $color-secondary-light;
- }
-
- &:focus {
- border: 2px solid $color-secondary-medium;
- }
-}
-
// #endregion
// #region transitions
diff --git a/assets/css/properties_panel/_vehicle_properties_panel.scss b/assets/css/properties_panel/_vehicle_properties_panel.scss
index cc8d2bc70..010be2a75 100644
--- a/assets/css/properties_panel/_vehicle_properties_panel.scss
+++ b/assets/css/properties_panel/_vehicle_properties_panel.scss
@@ -72,8 +72,7 @@
.m-vehicle-properties-panel__map-open-link {
position: absolute;
- // Above leaflet-panes
- z-index: 401;
+ z-index: #{$leaflet-pane-z-index + 1};
top: 10px;
// Adjacent to controls - control width is 40px
right: calc(env(safe-area-inset-right) + 40px + 0.5rem);
diff --git a/assets/src/components/card.tsx b/assets/src/components/card.tsx
index 079a338d1..5f0d16d19 100644
--- a/assets/src/components/card.tsx
+++ b/assets/src/components/card.tsx
@@ -1,25 +1,29 @@
-import React from "react"
+import React, { ReactElement, useId } from "react"
import { formattedTimeDiffUnderThreshold } from "../util/dateTime"
import { UnreadIcon } from "../helpers/icon"
import CloseButton from "./closeButton"
+import PropertiesList, { Property } from "./propertiesList"
export type CardStyle = "kiwi" | "white"
interface CardProps {
children?: React.ReactNode
+ icon?: React.ReactNode
style: CardStyle
currentTime?: Date
openCallback?: () => void
closeCallback?: () => void
isUnread?: boolean
additionalClass?: string
- title: string
+ title: string | ReactElement
time?: Date
noFocusOrHover?: boolean
+ selected?: boolean
}
export const Card: React.FC = ({
children,
+ icon,
style,
currentTime,
openCallback,
@@ -29,11 +33,14 @@ export const Card: React.FC = ({
title,
time,
noFocusOrHover,
+ selected,
}) => {
+ const labelId = "card-label-" + useId()
+
const innerLeftContent = (
- <>
+
-
+
{isUnread ? : null}
{title}
@@ -44,7 +51,7 @@ export const Card: React.FC
= ({
) : null}
{children}
- >
+
)
return (
@@ -53,15 +60,22 @@ export const Card: React.FC
= ({
`m-card m-card--${style}` +
(additionalClass ? " " + additionalClass : "") +
(noFocusOrHover ? " m-card--no-focus-or-hover" : "") +
- (!isUnread ? " m-card--read" : "")
+ (!isUnread ? " m-card--read" : "") +
+ (selected ? " m-card--selected" : "")
}
+ aria-current={selected}
+ aria-labelledby={labelId}
>
{openCallback ? (
+ {icon && {icon}
}
{innerLeftContent}
) : (
- {innerLeftContent}
+
+ {icon &&
{icon}
}
+ {innerLeftContent}
+
)}
{closeCallback ? (
@@ -76,38 +90,16 @@ export const CardBody: React.FC<{ children?: React.ReactNode }> = ({
children,
}) =>
{children}
-export interface Property {
- label: string
- value: string | null
- sensitive?: boolean
-}
-
export interface CardPropertiesProps {
properties: Property[]
+ highlightText?: string
}
export const CardProperties: React.VFC
= ({
properties,
+ highlightText,
}: CardPropertiesProps) => {
return (
-
- {properties.map((property) =>
- property.value ? (
-
- {property.label}
-
- {property.value}
-
-
- ) : null
- )}
-
+
)
}
diff --git a/assets/src/components/drawerTab.tsx b/assets/src/components/drawerTab.tsx
index 9f46521c1..aeb55296f 100644
--- a/assets/src/components/drawerTab.tsx
+++ b/assets/src/components/drawerTab.tsx
@@ -12,8 +12,8 @@ const DrawerTab = ({
{isVisible ? : }
diff --git a/assets/src/components/mapPage.tsx b/assets/src/components/mapPage.tsx
index 40c6ff401..f203f1d2a 100644
--- a/assets/src/components/mapPage.tsx
+++ b/assets/src/components/mapPage.tsx
@@ -15,6 +15,7 @@ import { useStations } from "../hooks/useStations"
import { isVehicle } from "../models/vehicle"
import { Vehicle, VehicleId, VehicleOrGhost } from "../realtime"
import { SearchPageState, setSelectedVehicle } from "../state/searchPageState"
+import DrawerTab from "./drawerTab"
import Map from "./map"
import RecentSearches from "./recentSearches"
import SearchForm from "./searchForm"
@@ -48,7 +49,7 @@ const ToggleMobileDisplayButton = ({
return (
Show {otherDisplayName} instead
@@ -71,6 +72,7 @@ const MapPage = (): ReactElement => {
const [selectedVehicleId, setSelectedVehicleId] = useState(
searchPageState.selectedVehicleId ?? null
)
+ const [searchOpen, setSearchOpen] = useState(true)
const liveVehicle: Vehicle | null = selectedVehicleId
? onlyVehicles.find((v) => v.id === selectedVehicleId) || null
@@ -110,6 +112,8 @@ const MapPage = (): ReactElement => {
const leafletMap = useRef(null)
useEffect(() => {
+ setSearchOpen(!vpcEnabled)
+
// Let leaflet know when Page resizes due to vpc state
leafletMap.current?.invalidateSize()
}, [vpcEnabled])
@@ -120,10 +124,15 @@ const MapPage = (): ReactElement => {
aria-label="Search Map Page"
>
+
setSearchOpen((a) => !a)}
+ />
=> {
/>
+
+
{vehicles !== null &&
thereIsAnActiveSearch(vehicles, searchPageState) ? (
diff --git a/assets/src/components/propertiesList.tsx b/assets/src/components/propertiesList.tsx
index c90a654ea..46aa76bbb 100644
--- a/assets/src/components/propertiesList.tsx
+++ b/assets/src/components/propertiesList.tsx
@@ -24,7 +24,10 @@ export const formattedLogonTime = (logonDate: Date): string => {
return `${formattedTimeDiff(nowDate, logonDate)}; ${formattedTime(logonDate)}`
}
-export const vehicleProperties = (vehicle: Vehicle): Property[] => {
+export const vehicleProperties = (
+ vehicle: Vehicle,
+ operatorLastNameOnly?: boolean
+): Property[] => {
const {
runId,
label,
@@ -35,7 +38,11 @@ export const vehicleProperties = (vehicle: Vehicle): Property[] => {
} = vehicle
const operatorValue =
- [operatorFirstName, operatorLastName, operatorId ? `#${operatorId}` : null]
+ [
+ operatorLastNameOnly ? null : operatorFirstName,
+ operatorLastName,
+ operatorId ? `#${operatorId}` : null,
+ ]
.filter((e) => e !== null)
.join(" ") || "Not Available"
@@ -76,10 +83,11 @@ export const ghostProperties = (ghost: Ghost): Property[] => [
]
export const vehicleOrGhostProperties = (
- vehicleOrGhost: VehicleOrGhost
+ vehicleOrGhost: VehicleOrGhost,
+ operatorLastNameOnly?: boolean
): Property[] =>
isVehicle(vehicleOrGhost)
- ? vehicleProperties(vehicleOrGhost)
+ ? vehicleProperties(vehicleOrGhost, operatorLastNameOnly)
: ghostProperties(vehicleOrGhost)
export const Highlighted = ({
diff --git a/assets/src/components/recentSearches.tsx b/assets/src/components/recentSearches.tsx
index 6fe637cec..912688a52 100644
--- a/assets/src/components/recentSearches.tsx
+++ b/assets/src/components/recentSearches.tsx
@@ -12,18 +12,21 @@ const RecentSearches = () => {
return (
Recent Searches
- {savedQueries.map((savedQuery, i) => (
-
{
- dispatch(setSearchText(savedQuery.text))
- dispatch(submitSearch())
- }}
- >
- {savedQuery.text}
-
- ))}
+
+ {savedQueries.map((savedQuery, i) => (
+
+ {
+ dispatch(setSearchText(savedQuery.text))
+ dispatch(submitSearch())
+ }}
+ >
+ {savedQuery.text}
+
+
+ ))}
+
)
}
diff --git a/assets/src/components/searchForm.tsx b/assets/src/components/searchForm.tsx
index 9d2c96896..d4c6ca8c8 100644
--- a/assets/src/components/searchForm.tsx
+++ b/assets/src/components/searchForm.tsx
@@ -76,7 +76,7 @@ const SearchForm = ({
@@ -102,7 +102,7 @@ const SearchForm = ({
/>
{property}
diff --git a/assets/src/components/searchResults.tsx b/assets/src/components/searchResults.tsx
index 6ed29dc8b..d861eda37 100644
--- a/assets/src/components/searchResults.tsx
+++ b/assets/src/components/searchResults.tsx
@@ -1,11 +1,12 @@
import React, { useContext } from "react"
import { StateDispatchContext } from "../contexts/stateDispatchContext"
-import { className } from "../helpers/dom"
-import { isRecentlyLoggedOn, isVehicle } from "../models/vehicle"
-import { Vehicle, VehicleOrGhost } from "../realtime"
+import { isVehicle } from "../models/vehicle"
+import { VehicleOrGhost } from "../realtime"
import { setSearchText } from "../state/searchPageState"
-import PropertiesList, { vehicleOrGhostProperties } from "./propertiesList"
+import { Card, CardProperties } from "./card"
+import { vehicleOrGhostProperties } from "./propertiesList"
import { RouteVariantName } from "./routeVariantName"
+import { VehicleStatusIcon } from "./vehicleRouteSummary"
interface Props {
vehicles: VehicleOrGhost[]
@@ -13,30 +14,6 @@ interface Props {
selectedVehicleId: string | null
}
-const SearchResultsNote = () => (
-
- Please note that at this time search is limited to active vehicles and
- logged-in personnel.
-
-)
-
-const NewBadge = () => (
-
- New
-
-
-
-
-
-
-)
-
-const RouteLabel = ({ vehicle }: { vehicle: Vehicle }) => (
-
-
-
-)
-
const SearchResultCard = ({
vehicleOrGhost,
onClick,
@@ -52,27 +29,21 @@ const SearchResultCard = ({
},
] = useContext(StateDispatchContext)
- const classes = [
- "m-search-results__card",
- isSelected ? "m-search-results__card--selected" : "",
- isRecentlyLoggedOn(vehicleOrGhost) ? "m-search-results__card--new" : "",
- ]
-
return (
- onClick(vehicleOrGhost)}
+ onClick(vehicleOrGhost)}
+ style="white"
+ title={ }
+ icon={ }
+ additionalClass="m-search-results__result"
+ selected={isSelected}
>
- {isRecentlyLoggedOn(vehicleOrGhost) && }
-
-
-
- {isVehicle(vehicleOrGhost) && }
-
+
)
}
@@ -120,21 +91,18 @@ const ResultsList = ({
onClick: (vehicle: VehicleOrGhost) => void
selectedVehicleId: string | null
}) => (
- <>
-
- {vehicles.sort(byOperatorLogonTime).map((vehicleOrGhost) => (
- onClick(vehicleOrGhost)}
- isSelected={
- selectedVehicleId ? selectedVehicleId === vehicleOrGhost.id : false
- }
- key={`search-result-card-${vehicleOrGhost.id}`}
- />
- ))}
-
-
- >
+
+ {vehicles.sort(byOperatorLogonTime).map((vehicleOrGhost) => (
+ onClick(vehicleOrGhost)}
+ isSelected={
+ selectedVehicleId ? selectedVehicleId === vehicleOrGhost.id : false
+ }
+ key={`search-result-card-${vehicleOrGhost.id}`}
+ />
+ ))}
+
)
const NoResults = () => {
@@ -154,7 +122,10 @@ const NoResults = () => {
again using numbers or last names only.
-
+
+ Please note that at this time search is limited to active vehicles and
+ logged-in personnel.
+
diff --git a/assets/tests/components/__snapshots__/appStateWrapper.test.tsx.snap b/assets/tests/components/__snapshots__/appStateWrapper.test.tsx.snap
index a222f9b95..af29d8305 100644
--- a/assets/tests/components/__snapshots__/appStateWrapper.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/appStateWrapper.test.tsx.snap
@@ -212,7 +212,7 @@ exports[`renders 1`] = `
>
diff --git a/assets/tests/components/__snapshots__/drawerTab.test.tsx.snap b/assets/tests/components/__snapshots__/drawerTab.test.tsx.snap
index 04ff43e02..454d01388 100644
--- a/assets/tests/components/__snapshots__/drawerTab.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/drawerTab.test.tsx.snap
@@ -6,8 +6,8 @@ exports[`drawerTab has correct icon when collapsed 1`] = `
>
@@ -137,7 +137,7 @@ exports[`LadderPage renders with route tabs 1`] = `
>
@@ -377,7 +377,7 @@ exports[`LadderPage renders with selectedRoutes in different order than routes d
>
@@ -637,7 +637,7 @@ exports[`LadderPage renders with timepoints 1`] = `
>
diff --git a/assets/tests/components/__snapshots__/mapPage.test.tsx.snap b/assets/tests/components/__snapshots__/mapPage.test.tsx.snap
index af9746a70..123b4886d 100644
--- a/assets/tests/components/__snapshots__/mapPage.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/mapPage.test.tsx.snap
@@ -8,8 +8,20 @@ exports[` Snapshot renders the empty state 1`] = `
>
+
+
+
+
+
+
+
@@ -39,7 +51,7 @@ exports[` Snapshot renders the empty state 1`] = `
Snapshot renders the empty state 1`] = `
value="all"
/>
all
@@ -84,7 +96,7 @@ exports[` Snapshot renders the empty state 1`] = `
value="run"
/>
run
@@ -101,7 +113,7 @@ exports[` Snapshot renders the empty state 1`] = `
value="vehicle"
/>
vehicle
@@ -118,7 +130,7 @@ exports[` Snapshot renders the empty state 1`] = `
value="operator"
/>
operator
@@ -128,11 +140,12 @@ exports[` Snapshot renders the empty state 1`] = `
Show map instead
+
@@ -144,6 +157,7 @@ exports[` Snapshot renders the empty state 1`] = `
>
Recent Searches
+
@@ -339,8 +353,20 @@ exports[` Snapshot renders the null state 1`] = `
>
+
+
+
+
+
+
+
@@ -370,7 +396,7 @@ exports[` Snapshot renders the null state 1`] = `
Snapshot renders the null state 1`] = `
value="all"
/>
all
@@ -415,7 +441,7 @@ exports[` Snapshot renders the null state 1`] = `
value="run"
/>
run
@@ -432,7 +458,7 @@ exports[` Snapshot renders the null state 1`] = `
value="vehicle"
/>
vehicle
@@ -449,7 +475,7 @@ exports[` Snapshot renders the null state 1`] = `
value="operator"
/>
operator
@@ -459,11 +485,12 @@ exports[` Snapshot renders the null state 1`] = `
Show map instead
+
@@ -475,6 +502,7 @@ exports[` Snapshot renders the null state 1`] = `
>
Recent Searches
+
@@ -670,8 +698,20 @@ exports[` Snapshot renders vehicle data 1`] = `
>
+
+
+
+
+
+
+
@@ -701,7 +741,7 @@ exports[` Snapshot renders vehicle data 1`] = `
Snapshot renders vehicle data 1`] = `
value="all"
/>
all
@@ -746,7 +786,7 @@ exports[` Snapshot renders vehicle data 1`] = `
value="run"
/>
run
@@ -763,7 +803,7 @@ exports[` Snapshot renders vehicle data 1`] = `
value="vehicle"
/>
vehicle
@@ -780,7 +820,7 @@ exports[` Snapshot renders vehicle data 1`] = `
value="operator"
/>
operator
@@ -790,11 +830,12 @@ exports[` Snapshot renders vehicle data 1`] = `
Show map instead
+
@@ -806,6 +847,7 @@ exports[` Snapshot renders vehicle data 1`] = `
>
Recent Searches
+
diff --git a/assets/tests/components/__snapshots__/notificationDrawer.test.tsx.snap b/assets/tests/components/__snapshots__/notificationDrawer.test.tsx.snap
index 9eec9b2e6..5fb5f2cb7 100644
--- a/assets/tests/components/__snapshots__/notificationDrawer.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/notificationDrawer.test.tsx.snap
@@ -96,6 +96,7 @@ exports[`NotificationDrawer renders notifications 1`] = `
-
",
+
+ ",
+ }
}
- }
- />
- No Operator
-
-
- 0 min
+ />
+ No Operator
+
+
+ 0 min
+
-
-
- OCC reported that an operator is not available on the r1, r2.
-
-
-
-
+ OCC reported that an operator is not available on the r1, r2.
+
+
+
- Run
-
-
- run1, run2
-
-
-
+
+
+
+ Run
+
+
+ run1, run2
+
+
+
+
+
+
diff --git a/assets/tests/components/__snapshots__/recentSearches.test.tsx.snap b/assets/tests/components/__snapshots__/recentSearches.test.tsx.snap
index 684061ab2..7e8a05168 100644
--- a/assets/tests/components/__snapshots__/recentSearches.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/recentSearches.test.tsx.snap
@@ -9,6 +9,7 @@ exports[`RecentSearches renders empty state 1`] = `
>
Recent Searches
+
`;
@@ -21,23 +22,31 @@ exports[`RecentSearches renders with data 1`] = `
>
Recent Searches
-
- poodle
-
-
- 999-502
-
-
- 999-501
-
+
+
+
+ poodle
+
+
+
+
+ 999-502
+
+
+
+
+ 999-501
+
+
+
`;
diff --git a/assets/tests/components/__snapshots__/searchForm.test.tsx.snap b/assets/tests/components/__snapshots__/searchForm.test.tsx.snap
index 7b9f3a0ba..9c36981f9 100644
--- a/assets/tests/components/__snapshots__/searchForm.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/searchForm.test.tsx.snap
@@ -34,7 +34,7 @@ exports[`SearchForm renders 1`] = `
all
@@ -87,7 +87,7 @@ exports[`SearchForm renders 1`] = `
value="run"
/>
run
@@ -106,7 +106,7 @@ exports[`SearchForm renders 1`] = `
value="vehicle"
/>
vehicle
@@ -125,7 +125,7 @@ exports[`SearchForm renders 1`] = `
value="operator"
/>
operator
diff --git a/assets/tests/components/__snapshots__/searchPage.test.tsx.snap b/assets/tests/components/__snapshots__/searchPage.test.tsx.snap
index c438584d0..b649076b7 100644
--- a/assets/tests/components/__snapshots__/searchPage.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/searchPage.test.tsx.snap
@@ -37,7 +37,7 @@ exports[`SearchPage renders the empty state 1`] = `
all
@@ -82,7 +82,7 @@ exports[`SearchPage renders the empty state 1`] = `
value="run"
/>
run
@@ -99,7 +99,7 @@ exports[`SearchPage renders the empty state 1`] = `
value="vehicle"
/>
vehicle
@@ -116,7 +116,7 @@ exports[`SearchPage renders the empty state 1`] = `
value="operator"
/>
operator
@@ -142,6 +142,7 @@ exports[`SearchPage renders the empty state 1`] = `
>
Recent Searches
+
@@ -344,7 +345,7 @@ exports[`SearchPage renders vehicle data 1`] = `
all
@@ -389,7 +390,7 @@ exports[`SearchPage renders vehicle data 1`] = `
value="run"
/>
run
@@ -406,7 +407,7 @@ exports[`SearchPage renders vehicle data 1`] = `
value="vehicle"
/>
vehicle
@@ -423,7 +424,7 @@ exports[`SearchPage renders vehicle data 1`] = `
value="operator"
/>
operator
@@ -449,6 +450,7 @@ exports[`SearchPage renders vehicle data 1`] = `
>
Recent Searches
+
diff --git a/assets/tests/components/__snapshots__/searchResults.test.tsx.snap b/assets/tests/components/__snapshots__/searchResults.test.tsx.snap
index 40ede0d8b..0d234eb3c 100644
--- a/assets/tests/components/__snapshots__/searchResults.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/searchResults.test.tsx.snap
@@ -8,137 +8,314 @@ exports[`SearchResults renders a list of results including vehicles and ghosts 1
className="m-search-results__list"
>
-
-
-
-
-
+
-
+ Vehicle Status Icon
+
+
- Run
-
-
+
+ 0123
+
+
+
+
+
+
+ X
+
+
+
+
+
+
+
+
+
+
+ 39_X
+
+
+
+ headsign
+
+
+
+
+
+
-
+
+
+
+ Run
+
+
+ 123-0123
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
-
- Run
-
-
- run-1
-
-
-
-
- Vehicle
-
-
+ Vehicle Status Icon
+
+
- v1-label
-
-
-
+
+ 1
+
+
+
+ X
+
+
+
+
+
+
+
+
-
- Operator
-
-
- PATTI SMITH #op1
-
-
-
+ 39_X
+
+
+
+ Forest Hills
+
+
+
+
+
+
-
- Last Login
-
-
- 4 hr 3 min; 1:38 PM
-
-
-
-
-
-
-
-
- 39_X
-
-
-
- Forest Hills
-
-
-
-
+
+
+
+ Run
+
+
+ run-1
+
+
+
+
+ Vehicle
+
+
+ v1-label
+
+
+
+
+ Operator
+
+
+ SMITH #op1
+
+
+
+
+ Last Login
+
+
+ 4 hr 3 min; 1:38 PM
+
+
+
+
+
+
+
+
+
-
- Please note that at this time search is limited to active vehicles and logged-in personnel.
-
`;
@@ -150,137 +327,319 @@ exports[`SearchResults renders a selected result card 1`] = `
className="m-search-results__list"
>
-
-
-
-
-
+
-
+ Vehicle Status Icon
+
+
- Run
-
-
+
+ 0123
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1_
+
+
+
+ headsign
+
+
+
+
+
+
-
+
+
+
+ Run
+
+
+ 123-0123
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
-
- Run
-
-
- run-1
-
-
-
-
- Vehicle
-
-
+ Vehicle Status Icon
+
+
- v1-label
-
-
-
+
+ 1
+
+
+
+ X
+
+
+
+
+
+
+
+
-
- Operator
-
-
- WILL SMITH #op1
-
-
-
+ 39_X
+
+
+
+ Forest Hills
+
+
+
+
+
+
-
- Last Login
-
-
- 4 hr 3 min; 1:38 PM
-
-
-
-
-
-
-
-
- 39_X
-
-
-
- Forest Hills
-
-
-
-
+
+
+
+ Run
+
+
+ run-1
+
+
+
+
+ Vehicle
+
+
+ v1-label
+
+
+
+
+ Operator
+
+
+ SMITH #op1
+
+
+
+
+ Last Login
+
+
+ 4 hr 3 min; 1:38 PM
+
+
+
+
+
+
+
+
+
-
- Please note that at this time search is limited to active vehicles and logged-in personnel.
-
`;
@@ -301,9 +660,7 @@ exports[`SearchResults renders no results 1`] = `
test
”. Please try again using numbers or last names only.
-
+
Please note that at this time search is limited to active vehicles and logged-in personnel.
`;
-
-exports[`SearchResults shows the new badge for vehicle that have logged in within the past 30 minutes 1`] = `
-
-
-
-
-
-
- New
-
-
-
-
-
-
-
-
-
-
-
-
- Run
-
-
- run-1
-
-
-
-
- Vehicle
-
-
- v1-label
-
-
-
-
- Operator
-
-
- PATTI SMITH #op1
-
-
-
-
- Last Login
-
-
- 1 min; 5:40 PM
-
-
-
-
-
-
-
-
- 39_X
-
-
-
- Forest Hills
-
-
-
-
-
-
-
- Please note that at this time search is limited to active vehicles and logged-in personnel.
-
-
-`;
diff --git a/assets/tests/components/__snapshots__/shuttleMapPage.test.tsx.snap b/assets/tests/components/__snapshots__/shuttleMapPage.test.tsx.snap
index 360a39857..b9c9f91b1 100644
--- a/assets/tests/components/__snapshots__/shuttleMapPage.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/shuttleMapPage.test.tsx.snap
@@ -14,7 +14,7 @@ exports[`Shuttle Map Page renders 1`] = `
>
@@ -399,7 +399,7 @@ exports[`Shuttle Map Page renders selected shuttle routes 1`] = `
>
@@ -784,7 +784,7 @@ exports[`Shuttle Map Page renders with all shuttles selected 1`] = `
>
@@ -1169,7 +1169,7 @@ exports[`Shuttle Map Page renders with shapes selected 1`] = `
>
@@ -1379,7 +1379,7 @@ exports[`Shuttle Map Page renders with train vehicles 1`] = `
>
diff --git a/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap b/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap
index 4a5b884b6..5580a67f9 100644
--- a/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap
+++ b/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap
@@ -10,8 +10,8 @@ exports[`ShuttlePicker renders 1`] = `
>
{
test("renders content", () => {
@@ -15,7 +16,8 @@ describe("Card", () => {
expect(result.queryByText(/Foo/)).not.toBeNull()
expect(result.queryByTitle("Close")).toBeNull()
expect(
- result.queryByText(/Foo/)?.parentElement?.parentElement?.className
+ result.queryByText(/Foo/)?.parentElement?.parentElement?.parentElement
+ ?.className
).toMatch(/m-card--read/)
})
@@ -49,7 +51,8 @@ describe("Card", () => {
)
expect(
- result.queryByText(/Foo/)?.parentElement?.parentElement?.className
+ result.queryByText(/Foo/)?.parentElement?.parentElement?.parentElement
+ ?.className
).toMatch(/my-custom-class/)
})
@@ -66,10 +69,28 @@ describe("Card", () => {
)
expect(
- result.queryByText(/Foo/)?.parentElement?.parentElement?.className
+ result.queryByText(/Foo/)?.parentElement?.parentElement?.parentElement
+ ?.className
).toMatch(/m-card--no-focus-or-hover/)
})
+ test("can mark as selected", () => {
+ const result = render(
+
+ Foo
+
+ )
+
+ expect(
+ result.getByRole("generic", { name: "My Card", current: true })
+ ).toBeInTheDocument()
+ })
+
test("includes age when time is given", () => {
const result = render(
{
expect(result.queryByText(/10 min/)).not.toBeNull()
})
+ test("includes icon element when given", () => {
+ const result = render(
+ Bar>} style="white">
+ Foo
+
+ )
+
+ expect(result.queryByText(/Bar/)).not.toBeNull()
+ })
+
+ test("includes icon element when given along with open callback", () => {
+ const result = render(
+ Bar>}
+ style="white"
+ openCallback={() => {
+ null
+ }}
+ >
+ Foo
+
+ )
+
+ expect(result.queryByText(/Bar/)).not.toBeNull()
+ })
+
test("invokes callback when clicked", async () => {
const openCallback = jest.fn()
const user = userEvent.setup()
@@ -99,9 +147,9 @@ describe("Card", () => {
)
- expect(result.getByText(/Contents/).parentElement?.tagName).toEqual(
- "BUTTON"
- )
+ expect(
+ result.getByText(/Contents/).parentElement?.parentElement?.tagName
+ ).toEqual("BUTTON")
await user.click(result.getByText(/Contents/))
@@ -181,8 +229,8 @@ describe("CardProperties", () => {
/>
)
- expect(result.queryByText(/Some sensitive value/)?.className).toMatch(
- /m-card__properties-value--sensitive fs-mask/
- )
+ expect(
+ result.queryByText(/Some sensitive value/)?.parentElement?.className
+ ).toMatch(/fs-mask/)
})
})
diff --git a/assets/tests/components/mapPage.test.tsx b/assets/tests/components/mapPage.test.tsx
index 39fe7f711..9a8f7759b 100644
--- a/assets/tests/components/mapPage.test.tsx
+++ b/assets/tests/components/mapPage.test.tsx
@@ -217,16 +217,12 @@ describe(" ", () => {
)
- const mapSearchPanel = screen.getByRole("generic", {
- name: /map search panel/i,
- })
- await userEvent.click(screen.getByRole("cell", { name: runId }))
+ await userEvent.click(screen.getByRole("cell", { name: "Run" }))
expect(
screen.getByRole("generic", { name: /vehicle properties card/i })
).toBeVisible()
expect(container.querySelector(".m-vehicle-map__route-shape")).toBeVisible()
- expect(mapSearchPanel).not.toBeVisible()
})
test("submitting a new search clears the previously selected route shape", async () => {
@@ -322,7 +318,7 @@ describe(" ", () => {
name: /vehicle properties card/i,
})
- expect(mapSearchPanel).not.toBeVisible()
+ expect(mapSearchPanel).toHaveClass("hidden")
expect(routeShape).toBeVisible()
expect(vehiclePropertiesCard).toBeVisible()
@@ -391,7 +387,7 @@ describe(" ", () => {
const mapSearchPanel = screen.getByRole("generic", {
name: /map search panel/i,
})
- expect(mapSearchPanel).toBeVisible()
+ expect(mapSearchPanel).toHaveClass("visible")
await userEvent.click(
screen.getByRole("button", {
@@ -402,7 +398,23 @@ describe(" ", () => {
expect(
screen.getByRole("generic", { name: /vehicle properties card/i })
).toBeVisible()
- expect(mapSearchPanel).not.toBeVisible()
+ expect(mapSearchPanel).toHaveClass("hidden")
+ })
+
+ test("can collapse and un-collapse the search panel with the drawer tab", async () => {
+ render( )
+
+ await userEvent.click(screen.getByRole("button", { name: "Collapse" }))
+
+ expect(screen.getByRole("generic", { name: /search panel/i })).toHaveClass(
+ "hidden"
+ )
+
+ await userEvent.click(screen.getByRole("button", { name: "Expand" }))
+
+ expect(screen.getByRole("generic", { name: /search panel/i })).toHaveClass(
+ "visible"
+ )
})
describe("VehiclePropertiesCard", () => {
diff --git a/assets/tests/components/pickerContainer.test.tsx b/assets/tests/components/pickerContainer.test.tsx
index 2f08be4f8..cf444b99e 100644
--- a/assets/tests/components/pickerContainer.test.tsx
+++ b/assets/tests/components/pickerContainer.test.tsx
@@ -20,7 +20,7 @@ describe("PickerContainer", () => {
expect(result.getByTestId("picker-container")).toHaveClass("visible")
expect(result.getByTestId("picker-container")).not.toHaveClass("hidden")
- await user.click(result.getByTestId("drawer-tab-button"))
+ await user.click(result.getByRole("button", { name: "Collapse" }))
expect(mockDispatch).toHaveBeenCalledWith(togglePickerContainer())
})
diff --git a/assets/tests/components/propertiesList.test.tsx b/assets/tests/components/propertiesList.test.tsx
index 862b8b897..eeef1a754 100644
--- a/assets/tests/components/propertiesList.test.tsx
+++ b/assets/tests/components/propertiesList.test.tsx
@@ -157,6 +157,12 @@ describe("vehicleOrGhostProperties", () => {
)
})
+ test("uses vehicle properties for vehicles, operator last name only", () => {
+ expect(vehicleOrGhostProperties(vehicle, true)).toEqual(
+ vehicleProperties(vehicle, true)
+ )
+ })
+
test("uses ghost properties for ghosts", () => {
expect(vehicleOrGhostProperties(ghost)).toEqual(ghostProperties(ghost))
})
@@ -219,6 +225,21 @@ describe("vehicleProperties", () => {
)
})
+ test("operator information gives last name if that's all that's available", () => {
+ const properties = vehicleProperties(
+ vehicleFactory.build({
+ operatorFirstName: "JOHN",
+ operatorLastName: "SMITH",
+ operatorId: "1234",
+ }),
+ true
+ )
+
+ expect(properties.find((prop) => prop.label === "Operator")!.value).toEqual(
+ "SMITH #1234"
+ )
+ })
+
test("operator information is marked sensitive", () => {
const vehicle = vehicleFactory.build()
diff --git a/assets/tests/components/searchResults.test.tsx b/assets/tests/components/searchResults.test.tsx
index 628e81ee0..72eb7b396 100644
--- a/assets/tests/components/searchResults.test.tsx
+++ b/assets/tests/components/searchResults.test.tsx
@@ -1,4 +1,4 @@
-import { render } from "@testing-library/react"
+import { render, screen } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import React from "react"
import renderer from "react-test-renderer"
@@ -10,9 +10,10 @@ import { Ghost, Vehicle } from "../../src/realtime"
import { initialState, State } from "../../src/state"
import { setSearchText } from "../../src/state/searchPageState"
import * as dateTime from "../../src/util/dateTime"
+import "@testing-library/jest-dom"
import ghostFactory from "../factories/ghost"
-import vehicleFactory from "../factories/vehicle"
+import vehicleFactory, { shuttleFactory } from "../factories/vehicle"
jest
.spyOn(dateTime, "now")
@@ -133,77 +134,6 @@ describe("SearchResults", () => {
expect(tree).toMatchSnapshot()
})
- test("shows the new badge for vehicle that have logged in within the past 30 minutes", () => {
- const vehicle: Vehicle = vehicleFactory.build({
- id: "v1",
- label: "v1-label",
- runId: "run-1",
- timestamp: 123,
- latitude: 0,
- longitude: 0,
- directionId: 0,
- routeId: "39",
- tripId: "t1",
- headsign: "Forest Hills",
- viaVariant: "X",
- operatorId: "op1",
- operatorFirstName: "PATTI",
- operatorLastName: "SMITH",
- operatorLogonTime: new Date("2018-08-15T17:40:21.000Z"),
- bearing: 33,
- blockId: "block-1",
- previousVehicleId: "v2",
- scheduleAdherenceSecs: 0,
- isShuttle: false,
- isOverload: false,
- isOffCourse: false,
- isRevenue: true,
- layoverDepartureTime: null,
- dataDiscrepancies: [
- {
- attribute: "trip_id",
- sources: [
- {
- id: "swiftly",
- value: "swiftly-trip-id",
- },
- {
- id: "busloc",
- value: "busloc-trip-id",
- },
- ],
- },
- ],
- stopStatus: {
- stopId: "s1",
- stopName: "Stop Name",
- },
- timepointStatus: {
- fractionUntilTimepoint: 0.5,
- timepointId: "tp1",
- },
- scheduledLocation: null,
- routeStatus: "on_route",
- endOfTripType: "another_trip",
- blockWaivers: [],
- crowding: null,
- })
-
- const tree = renderer
- .create(
-
-
-
- )
- .toJSON()
-
- expect(tree).toMatchSnapshot()
- })
-
test("sorts vehicles by most recent operator logon time, ghosts at the top", () => {
const oldVehicle: Vehicle = vehicleFactory.build({
id: "old",
@@ -347,6 +277,22 @@ describe("SearchResults", () => {
expect(JSON.stringify(tree)).toMatch(/ghost-run.*new-label.*old-label/)
})
+ test("renders a shuttle", () => {
+ const vehicle: Vehicle = shuttleFactory.build()
+
+ render(
+
+
+
+ )
+
+ expect(screen.getByText(/Shuttle/)).toBeInTheDocument()
+ })
+
test("renders a selected result card", () => {
const vehicle: Vehicle = vehicleFactory.build({
runId: "run-1",
@@ -374,7 +320,7 @@ describe("SearchResults", () => {
const testDispatch = jest.fn()
const vehicle: Vehicle = vehicleFactory.build({ runId: "12345" })
const mockOnClick = jest.fn()
- const result = render(
+ render(
{
)
- await userEvent.click(result.getByText("12345"))
+ await userEvent.click(screen.getByRole("cell", { name: /run/i }))
expect(mockOnClick).toHaveBeenCalledWith(vehicle)
})
diff --git a/assets/tests/components/shuttlePickerContainer.test.tsx b/assets/tests/components/shuttlePickerContainer.test.tsx
index 2464d44d1..6cb9eebc4 100644
--- a/assets/tests/components/shuttlePickerContainer.test.tsx
+++ b/assets/tests/components/shuttlePickerContainer.test.tsx
@@ -21,7 +21,7 @@ describe("ShuttlePickerContainer", () => {
"visible"
)
- await user.click(result.getByTestId("drawer-tab-button"))
+ await user.click(result.getByRole("button", { name: "Collapse" }))
expect(mockDispatch).toHaveBeenCalledWith(togglePickerContainer())
})