diff --git a/assets/css/colors.scss b/assets/css/colors.scss
index 36a4f2b44..f8cba103b 100644
--- a/assets/css/colors.scss
+++ b/assets/css/colors.scss
@@ -13,6 +13,7 @@ $true-grey-45: #737373;
$true-grey-70: #b2b1af;
$warm-neutral-80: #cccbc8;
+$warm-neutral-85: #d9d6d0;
$warm-neutral-90: #e5e4e1;
$cool-black-15: #171f26;
diff --git a/assets/css/elevator_v2.scss b/assets/css/elevator_v2.scss
index 06f089c72..ce9f5d94f 100644
--- a/assets/css/elevator_v2.scss
+++ b/assets/css/elevator_v2.scss
@@ -42,7 +42,7 @@ body {
}
}
-.outside-elevator-closures,
+.elevator-closures-list,
.current-elevator-closed {
position: relative;
display: flex;
@@ -51,21 +51,6 @@ body {
color: $cool-black-15;
background-color: $warm-neutral-90;
- hr.thick {
- min-height: 24px;
- margin: 0;
- background-color: $cool-black-15;
- border: none;
- }
-
- hr.thin {
- min-height: 2px;
- margin: 24px 0;
- background-color: $true-grey-45;
- border: none;
- opacity: 0.5;
- }
-
.subheading {
font-size: 80px;
font-weight: 700;
@@ -84,4 +69,4 @@ body {
}
@import "v2/elevator/current_elevator_closed";
-@import "v2/elevator/outside_elevator_closures";
+@import "v2/elevator/elevator_closures_list";
diff --git a/assets/css/v2/elevator/outside_elevator_closures.scss b/assets/css/v2/elevator/elevator_closures_list.scss
similarity index 72%
rename from assets/css/v2/elevator/outside_elevator_closures.scss
rename to assets/css/v2/elevator/elevator_closures_list.scss
index 077f6ce2a..a37f9c3fd 100644
--- a/assets/css/v2/elevator/outside_elevator_closures.scss
+++ b/assets/css/v2/elevator/elevator_closures_list.scss
@@ -1,9 +1,10 @@
-.outside-elevator-closures {
+.elevator-closures-list {
display: flex;
flex: 1;
flex-direction: column;
.in-station-summary {
+ position: relative;
display: flex;
justify-content: space-between;
padding: 24px 48px;
@@ -15,9 +16,19 @@
.text {
margin-right: 82px;
}
+
+ &::after {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ height: 24px;
+ content: "";
+ background: $cool-black-15;
+ }
}
- .outside-closure-list {
+ .closures-list {
height: 100%;
background-color: $warm-neutral-90;
@@ -49,8 +60,35 @@
transform: translateX(calc(-100% * var(--closure-list-offset)));
.closure-row {
+ position: relative;
width: 1080px;
- padding: 0 48px;
+ padding: 26px 48px 24px;
+
+ &:not(&--current-station) {
+ &::after,
+ &:first-child::before {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ margin: 0 24px;
+ content: "";
+ background: $true-grey-45;
+ opacity: 0.5;
+ }
+
+ &::after {
+ top: 100%;
+ }
+
+ &::before {
+ top: 0;
+ }
+ }
+
+ &--current-station {
+ background-color: $warm-neutral-85;
+ }
&__station-name {
font-size: 62px;
diff --git a/assets/package-lock.json b/assets/package-lock.json
index 61a5b28d8..a3e21d2ce 100644
--- a/assets/package-lock.json
+++ b/assets/package-lock.json
@@ -38,6 +38,7 @@
"@sentry/webpack-plugin": "^2.22.6",
"@svgr/webpack": "^5.5.0",
"@types/lodash": "^4.17.13",
+ "@types/number-to-words": "^1.2.3",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"@types/react-router-dom": "^5.1.8",
@@ -4423,6 +4424,13 @@
"undici-types": "~5.26.4"
}
},
+ "node_modules/@types/number-to-words": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@types/number-to-words/-/number-to-words-1.2.3.tgz",
+ "integrity": "sha512-ruSA/QZ6JQofoEEN2zKmN9oihZmrCBgcw0zEzN0UA9Mw0pU5remTddZmrbHjsa99qz12Uxl82x+XkVpHu87oXw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/parse-json": {
"version": "4.0.0",
"dev": true,
diff --git a/assets/package.json b/assets/package.json
index a949db536..e2372b20d 100644
--- a/assets/package.json
+++ b/assets/package.json
@@ -50,6 +50,7 @@
"@sentry/webpack-plugin": "^2.22.6",
"@svgr/webpack": "^5.5.0",
"@types/lodash": "^4.17.13",
+ "@types/number-to-words": "^1.2.3",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"@types/react-router-dom": "^5.1.8",
diff --git a/assets/src/apps/v2/elevator.tsx b/assets/src/apps/v2/elevator.tsx
index b43342a35..c05963ec5 100644
--- a/assets/src/apps/v2/elevator.tsx
+++ b/assets/src/apps/v2/elevator.tsx
@@ -14,7 +14,7 @@ import EvergreenContent from "Components/v2/evergreen_content";
import ScreenPage from "Components/v2/screen_page";
import { MappingContext } from "Components/v2/widget";
import MultiScreenPage from "Components/v2/multi_screen_page";
-import OutsideElevatorClosures from "Components/v2/elevator/outside_elevator_closures";
+import ElevatorClosuresList from "Components/v2/elevator/elevator_closures_list";
import CurrentElevatorClosed from "Components/v2/elevator/current_elevator_closed";
import SimulationScreenPage from "Components/v2/simulation_screen_page";
import Footer from "Components/v2/elevator/footer";
@@ -22,7 +22,7 @@ import NormalHeader from "Components/v2/normal_header";
const TYPE_TO_COMPONENT = {
normal: NormalScreen,
- outside_elevator_closures: OutsideElevatorClosures,
+ elevator_closures_list: ElevatorClosuresList,
current_elevator_closed: CurrentElevatorClosed,
evergreen_content: EvergreenContent,
footer: Footer,
diff --git a/assets/src/components/v2/elevator/outside_elevator_closures.tsx b/assets/src/components/v2/elevator/elevator_closures_list.tsx
similarity index 63%
rename from assets/src/components/v2/elevator/outside_elevator_closures.tsx
rename to assets/src/components/v2/elevator/elevator_closures_list.tsx
index 2618911ae..66b88a372 100644
--- a/assets/src/components/v2/elevator/outside_elevator_closures.tsx
+++ b/assets/src/components/v2/elevator/elevator_closures_list.tsx
@@ -13,11 +13,34 @@ import {
import useClientPaging from "Hooks/v2/use_client_paging";
import NormalService from "Images/svgr_bundled/normal-service.svg";
import AccessibilityAlert from "Images/svgr_bundled/accessibility-alert.svg";
+import { classWithModifier } from "Util/util";
interface ClosureRowProps {
station: StationWithClosures;
}
+const CurrentStationClosureRow = ({ station }: ClosureRowProps) => {
+ const { closures } = station;
+
+ return (
+
-
+
+ s.id === stationId)
+ .flatMap((s) => s.closures)}
+ />
@@ -166,5 +224,5 @@ const OutsideElevatorClosures = ({
};
export default makePersistent(
- OutsideElevatorClosures as ComponentType,
+ ElevatorClosuresList as ComponentType,
);
diff --git a/lib/screens/v2/candidate_generator/elevator/closures.ex b/lib/screens/v2/candidate_generator/elevator/closures.ex
index 20c02e85e..eafb328eb 100644
--- a/lib/screens/v2/candidate_generator/elevator/closures.ex
+++ b/lib/screens/v2/candidate_generator/elevator/closures.ex
@@ -10,9 +10,9 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
alias Screens.V2.WidgetInstance.{
CurrentElevatorClosed,
+ ElevatorClosuresList,
Footer,
- NormalHeader,
- OutsideElevatorClosures
+ NormalHeader
}
alias Screens.V2.WidgetInstance.Elevator.Closure
@@ -50,21 +50,23 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
elevator_alerts = Enum.filter(alerts, &relevant_alert?(&1, stop_id))
routes_map = get_routes_map(elevator_alerts, stop_id)
- {in_station_alerts, outside_alerts} =
- split_closures_by_location(elevator_alerts, stop_id)
-
- in_station_closures =
- Enum.map(in_station_alerts, &alert_to_elevator_closure/1)
-
- current_elevator_closure = Enum.find(in_station_closures, &(&1.elevator_id == elevator_id))
+ current_elevator_closure =
+ elevator_alerts
+ |> get_in_station_alerts(stop_id)
+ |> Enum.map(&alert_to_elevator_closure/1)
+ |> Enum.find(&(&1.elevator_id == elevator_id))
{elevator_widget_instance, header_footer_variant} =
if is_nil(current_elevator_closure) do
- {%OutsideElevatorClosures{
- in_station_closures: in_station_closures,
- other_stations_with_closures:
- format_outside_closures(outside_alerts, parent_station_map, routes_map),
- app_params: config
+ {%ElevatorClosuresList{
+ stations_with_closures:
+ build_stations_with_closures(
+ elevator_alerts,
+ parent_station_map,
+ routes_map
+ ),
+ app_params: config,
+ station_id: stop_id
}, nil}
else
{%CurrentElevatorClosed{closure: current_elevator_closure, app_params: config}, :closed}
@@ -133,8 +135,8 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
|> Enum.uniq()
end
- defp split_closures_by_location(closures, home_stop_id) do
- Enum.split_with(closures, fn %Alert{informed_entities: informed_entities} ->
+ defp get_in_station_alerts(alerts, home_stop_id) do
+ Enum.filter(alerts, fn %Alert{informed_entities: informed_entities} ->
home_stop_id in Enum.map(informed_entities, & &1.stop)
end)
end
@@ -156,18 +158,18 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
}
end
- defp format_outside_closures(closures, station_id_to_name, station_id_to_routes) do
- closures
+ defp build_stations_with_closures(alerts, station_id_to_name, station_id_to_routes) do
+ alerts
|> Enum.group_by(&get_parent_station_id_from_informed_entities(&1.informed_entities))
- |> Enum.map(fn {parent_station_id, closures} ->
- closures_at_station = Enum.map(closures, &alert_to_elevator_closure/1)
+ |> Enum.map(fn {parent_station_id, alerts} ->
+ closures_at_station = Enum.map(alerts, &alert_to_elevator_closure/1)
route_pills =
station_id_to_routes
|> Map.fetch!(parent_station_id)
|> Enum.map(&RoutePill.serialize_icon/1)
- %OutsideElevatorClosures.Station{
+ %ElevatorClosuresList.Station{
id: parent_station_id,
name: Map.fetch!(station_id_to_name, parent_station_id),
route_icons: route_pills,
diff --git a/lib/screens/v2/widget_instance/outside_elevator_closures.ex b/lib/screens/v2/widget_instance/elevator_closures_list.ex
similarity index 57%
rename from lib/screens/v2/widget_instance/outside_elevator_closures.ex
rename to lib/screens/v2/widget_instance/elevator_closures_list.ex
index bcc2f12e1..43143fc11 100644
--- a/lib/screens/v2/widget_instance/outside_elevator_closures.ex
+++ b/lib/screens/v2/widget_instance/elevator_closures_list.ex
@@ -1,16 +1,16 @@
-defmodule Screens.V2.WidgetInstance.OutsideElevatorClosures do
+defmodule Screens.V2.WidgetInstance.ElevatorClosuresList do
@moduledoc false
alias Screens.Stops.Stop
alias Screens.V2.WidgetInstance.Elevator.Closure
alias ScreensConfig.V2.Elevator
- defstruct ~w[app_params in_station_closures other_stations_with_closures]a
+ defstruct ~w[app_params stations_with_closures station_id]a
@type t :: %__MODULE__{
app_params: Elevator.t(),
- in_station_closures: list(Closure.t()),
- other_stations_with_closures: list(__MODULE__.Station.t())
+ stations_with_closures: list(__MODULE__.Station.t()),
+ station_id: String.t()
}
defmodule Station do
@@ -33,26 +33,26 @@ defmodule Screens.V2.WidgetInstance.OutsideElevatorClosures do
def serialize(%__MODULE__{
app_params: %Elevator{elevator_id: id},
- in_station_closures: in_station_closures,
- other_stations_with_closures: other_stations_with_closures
+ stations_with_closures: stations_with_closures,
+ station_id: station_id
}),
do: %{
id: id,
- in_station_closures: in_station_closures,
- other_stations_with_closures: other_stations_with_closures
+ stations_with_closures: stations_with_closures,
+ station_id: station_id
}
defimpl Screens.V2.WidgetInstance do
- alias Screens.V2.WidgetInstance.OutsideElevatorClosures
+ alias Screens.V2.WidgetInstance.ElevatorClosuresList
def priority(_instance), do: [1]
- def serialize(instance), do: OutsideElevatorClosures.serialize(instance)
+ def serialize(instance), do: ElevatorClosuresList.serialize(instance)
def slot_names(_instance), do: [:main_content]
- def widget_type(_instance), do: :outside_elevator_closures
+ def widget_type(_instance), do: :elevator_closures_list
def valid_candidate?(_instance), do: true
def audio_serialize(_instance), do: %{}
def audio_sort_key(_instance), do: [0]
def audio_valid_candidate?(_instance), do: false
- def audio_view(_instance), do: ScreensWeb.V2.Audio.OutsideElevatorClosuresView
+ def audio_view(_instance), do: ScreensWeb.V2.Audio.ElevatorClosuresListView
end
end
diff --git a/lib/screens_web/views/v2/audio/outside_elevator_closures_view.ex b/lib/screens_web/views/v2/audio/elevator_closures_list_view.ex
similarity index 56%
rename from lib/screens_web/views/v2/audio/outside_elevator_closures_view.ex
rename to lib/screens_web/views/v2/audio/elevator_closures_list_view.ex
index bfee0f336..d902ef91b 100644
--- a/lib/screens_web/views/v2/audio/outside_elevator_closures_view.ex
+++ b/lib/screens_web/views/v2/audio/elevator_closures_list_view.ex
@@ -1,4 +1,4 @@
-defmodule ScreensWeb.V2.Audio.OutsideElevatorClosuresView do
+defmodule ScreensWeb.V2.Audio.ElevatorClosuresListView do
use ScreensWeb, :view
def render("_widget.ssml", _) do
diff --git a/test/screens/v2/candidate_generator/elevator/closures_test.exs b/test/screens/v2/candidate_generator/elevator/closures_test.exs
index eced7377b..a12401dcf 100644
--- a/test/screens/v2/candidate_generator/elevator/closures_test.exs
+++ b/test/screens/v2/candidate_generator/elevator/closures_test.exs
@@ -11,7 +11,7 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
CurrentElevatorClosed,
Footer,
NormalHeader,
- OutsideElevatorClosures
+ ElevatorClosuresList
}
alias ScreensConfig.Screen
@@ -83,18 +83,23 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
[
^header_instance,
- %OutsideElevatorClosures{
+ %ElevatorClosuresList{
app_params: ^config,
- in_station_closures: [
- %{
- id: "1",
- description: nil,
- elevator_name: "Test",
- elevator_id: "facility-test",
- header_text: nil
+ stations_with_closures: [
+ %ElevatorClosuresList.Station{
+ id: "place-test",
+ name: "Place Test",
+ route_icons: [%{type: :text, text: "RL", color: :red}],
+ closures: [
+ %Closure{
+ id: "1",
+ elevator_name: "Test",
+ elevator_id: "facility-test"
+ }
+ ]
}
],
- other_stations_with_closures: []
+ station_id: "place-test"
},
^footer_instance
] =
@@ -147,10 +152,9 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
[
^header_instance,
- %OutsideElevatorClosures{
+ %ElevatorClosuresList{
app_params: ^config,
- in_station_closures: [],
- other_stations_with_closures: [
+ stations_with_closures: [
%{
id: "place-haecl",
name: "Haymarket",
@@ -220,10 +224,9 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
[
^header_instance,
- %OutsideElevatorClosures{
+ %ElevatorClosuresList{
app_params: ^config,
- in_station_closures: [],
- other_stations_with_closures: []
+ stations_with_closures: []
},
^footer_instance
] =
@@ -288,7 +291,7 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
[
^header_instance,
- %Screens.V2.WidgetInstance.OutsideElevatorClosures{
+ %ElevatorClosuresList{
app_params: %ScreensConfig.V2.Elevator{
elevator_id: "111",
alternate_direction_text: "Test",
@@ -297,22 +300,25 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
accessible_path_image_url: nil,
accessible_path_image_here_coordinates: %{y: 0, x: 0}
},
- in_station_closures: [
- %Screens.V2.WidgetInstance.Elevator.Closure{
- id: "1",
- elevator_name: "In Station Elevator",
- elevator_id: "112",
- description: nil,
- header_text: nil
- }
- ],
- other_stations_with_closures: [
- %Screens.V2.WidgetInstance.OutsideElevatorClosures.Station{
+ stations_with_closures: [
+ %ElevatorClosuresList.Station{
+ id: "place-test",
+ name: "This Station",
+ route_icons: [%{type: :text, text: "RL", color: :red}],
+ closures: [
+ %Closure{
+ id: "1",
+ elevator_name: "In Station Elevator",
+ elevator_id: "112"
+ }
+ ]
+ },
+ %ElevatorClosuresList.Station{
id: "place-test-no-redundancy",
name: "Other No Redundancy",
route_icons: [%{type: :text, text: "RL", color: :red}],
closures: [
- %Screens.V2.WidgetInstance.Elevator.Closure{
+ %Closure{
id: "3",
elevator_name: "Other Without Redundancy",
elevator_id: "333",
@@ -321,7 +327,8 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
}
]
}
- ]
+ ],
+ station_id: "place-test"
},
^footer_instance
] =
@@ -422,18 +429,22 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
[
^header_instance,
- %OutsideElevatorClosures{
+ %ElevatorClosuresList{
app_params: ^config,
- in_station_closures: [
- %{
- id: "1",
- description: nil,
- elevator_name: "Test",
- elevator_id: "facility-test",
- header_text: nil
+ stations_with_closures: [
+ %ElevatorClosuresList.Station{
+ id: "place-test",
+ name: "Place Test",
+ closures: [
+ %Closure{
+ id: "1",
+ elevator_name: "Test",
+ elevator_id: "facility-test"
+ }
+ ]
}
],
- other_stations_with_closures: []
+ station_id: "place-test"
},
^footer_instance
] =
diff --git a/test/screens/v2/widget_instance/outside_elevator_closures_test.exs b/test/screens/v2/widget_instance/elevator_closures_list_test.exs
similarity index 65%
rename from test/screens/v2/widget_instance/outside_elevator_closures_test.exs
rename to test/screens/v2/widget_instance/elevator_closures_list_test.exs
index ee8397206..72dd3f2ac 100644
--- a/test/screens/v2/widget_instance/outside_elevator_closures_test.exs
+++ b/test/screens/v2/widget_instance/elevator_closures_list_test.exs
@@ -1,31 +1,22 @@
-defmodule Screens.V2.WidgetInstance.OutsideElevatorClosuresTest do
+defmodule Screens.V2.WidgetInstance.ElevatorClosuresListTest do
use ExUnit.Case, async: true
alias Screens.V2.WidgetInstance
alias Screens.V2.WidgetInstance.Elevator.Closure
- alias Screens.V2.WidgetInstance.OutsideElevatorClosures
+ alias Screens.V2.WidgetInstance.ElevatorClosuresList
alias ScreensConfig.V2.Elevator
setup do
%{
- instance: %OutsideElevatorClosures{
+ instance: %ElevatorClosuresList{
app_params:
struct(Elevator,
elevator_id: "1",
alternate_direction_text: "Test",
accessible_path_direction_arrow: :n
),
- in_station_closures: [
- %Closure{
- description: "Test Alert Description",
- elevator_name: "Test Elevator",
- elevator_id: "111",
- id: "1",
- header_text: "Test Alert Header"
- }
- ],
- other_stations_with_closures: [
- %OutsideElevatorClosures.Station{
+ stations_with_closures: [
+ %ElevatorClosuresList.Station{
name: "Forest Hills",
route_icons: ["Orange"],
closures: [
@@ -52,9 +43,9 @@ defmodule Screens.V2.WidgetInstance.OutsideElevatorClosuresTest do
describe "serialize/1" do
test "returns map with id and closures", %{instance: instance} do
assert %{
- in_station_closures: instance.in_station_closures,
- other_stations_with_closures: instance.other_stations_with_closures,
- id: instance.app_params.elevator_id
+ stations_with_closures: instance.stations_with_closures,
+ id: instance.app_params.elevator_id,
+ station_id: nil
} == WidgetInstance.serialize(instance)
end
end
@@ -66,8 +57,8 @@ defmodule Screens.V2.WidgetInstance.OutsideElevatorClosuresTest do
end
describe "widget_type/1" do
- test "returns outside_elevator_closures", %{instance: instance} do
- assert :outside_elevator_closures == WidgetInstance.widget_type(instance)
+ test "returns elevator_closures_list", %{instance: instance} do
+ assert :elevator_closures_list == WidgetInstance.widget_type(instance)
end
end
@@ -90,8 +81,8 @@ defmodule Screens.V2.WidgetInstance.OutsideElevatorClosuresTest do
end
describe "audio_view/1" do
- test "returns OutsideElevatorClosuresView", %{instance: instance} do
- assert ScreensWeb.V2.Audio.OutsideElevatorClosuresView ==
+ test "returns ElevatorClosuresListView", %{instance: instance} do
+ assert ScreensWeb.V2.Audio.ElevatorClosuresListView ==
WidgetInstance.audio_view(instance)
end
end