diff --git a/assets/css/colors.scss b/assets/css/colors.scss
index b4b0fb251..36a4f2b44 100644
--- a/assets/css/colors.scss
+++ b/assets/css/colors.scss
@@ -19,3 +19,5 @@ $cool-black-15: #171f26;
$cool-black-30: #2e3e4d;
$normal-service-green: #145a06;
+
+$accessibility-blue: #165c96;
diff --git a/assets/css/elevator_v2.scss b/assets/css/elevator_v2.scss
index 5a0ea16c4..06f089c72 100644
--- a/assets/css/elevator_v2.scss
+++ b/assets/css/elevator_v2.scss
@@ -1,13 +1,17 @@
+// Our Mimo elevator screens run Webview 83.
+// When writing styles for widgets on these screens,
+// verify browser compatibility in the MDN web docs.
+
@import "https://rsms.me/inter/inter.css";
@import "colors";
@import "v2/lcd_common/screen_container";
-@import "v2/elevator/elevator_closures";
@import "v2/elevator/normal";
@import "v2/simulation_common";
@import "v2/lcd_common/simulation";
@import "v2/elevator/header";
@import "v2/elevator/footer";
@import "v2/lcd_common/route_pill";
+@import "v2/arrow";
.evergreen-content-image__container,
.evergreen-content-image__image {
@@ -23,3 +27,61 @@ body {
.multi-screen-page {
grid-auto-rows: 1920px;
}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+.normal-header,
+.footer {
+ &--closed {
+ color: white;
+ background-color: $accessibility-blue;
+ }
+}
+
+.outside-elevator-closures,
+.current-elevator-closed {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ 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;
+ line-height: 80px;
+ }
+}
+
+.paging-indicators {
+ display: flex;
+ align-items: center;
+ margin-right: 66px;
+
+ .paging-indicator:first-child:not(:only-child) {
+ margin-right: 27px;
+ }
+}
+
+@import "v2/elevator/current_elevator_closed";
+@import "v2/elevator/outside_elevator_closures";
diff --git a/assets/css/v2/elevator/current_elevator_closed.scss b/assets/css/v2/elevator/current_elevator_closed.scss
new file mode 100644
index 000000000..acaa23595
--- /dev/null
+++ b/assets/css/v2/elevator/current_elevator_closed.scss
@@ -0,0 +1,129 @@
+.current-elevator-closed {
+ position: relative;
+ height: 100%;
+
+ .notch {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: inline-block;
+ border-right: 345px solid $accessibility-blue;
+ border-bottom: 300px solid transparent;
+ }
+
+ .header {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 528px;
+ padding-left: 48px;
+ font-weight: 700;
+
+ .icons {
+ margin-bottom: 21px;
+
+ .no-service-icon {
+ margin-right: 16px;
+ }
+ }
+
+ .closed-text {
+ margin-bottom: 18px;
+ font-size: 150px;
+ line-height: 150px;
+ }
+ }
+
+ hr.thin {
+ margin: 0 20px;
+ }
+
+ .accessible-path-container {
+ height: 984px;
+ padding: 48px;
+
+ .subheading-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 142px;
+
+ .subheading {
+ align-self: center;
+ }
+
+ .arrow {
+ width: 100px;
+ height: 100px;
+ }
+ }
+
+ .alternate-direction-text {
+ color: $cool-black-30;
+
+ &.small {
+ font-size: 48px;
+ line-height: 64px;
+ }
+
+ &.medium {
+ font-size: 62px;
+ line-height: 80px;
+ }
+
+ &.large {
+ font-size: 80px;
+ line-height: 96px;
+ }
+ }
+
+ .map-container {
+ position: relative;
+ margin-top: 26px;
+ margin-left: -48px;
+
+ .map {
+ width: 1080px;
+ }
+ }
+ }
+
+ .paging-indicators {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ height: 120px;
+ }
+}
+
+.marker-container {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 116px;
+ height: 116px;
+
+ .marker-background,
+ .marker {
+ position: absolute;
+ }
+
+ .marker-background {
+ animation: pulse-ring 1.5s infinite;
+ }
+}
+
+@keyframes pulse-ring {
+ 0% {
+ transform: scale(0.5);
+ }
+
+ 60% {
+ opacity: 0.25;
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
diff --git a/assets/css/v2/elevator/footer.scss b/assets/css/v2/elevator/footer.scss
index 77d4264eb..86a964854 100644
--- a/assets/css/v2/elevator/footer.scss
+++ b/assets/css/v2/elevator/footer.scss
@@ -1,5 +1,4 @@
.footer {
- box-sizing: border-box;
height: 100%;
padding: 26px 48px;
font-size: 48px;
diff --git a/assets/css/v2/elevator/elevator_closures.scss b/assets/css/v2/elevator/outside_elevator_closures.scss
similarity index 79%
rename from assets/css/v2/elevator/elevator_closures.scss
rename to assets/css/v2/elevator/outside_elevator_closures.scss
index 0ce4ea92a..077f6ce2a 100644
--- a/assets/css/v2/elevator/elevator_closures.scss
+++ b/assets/css/v2/elevator/outside_elevator_closures.scss
@@ -1,9 +1,7 @@
-.elevator-closures {
- position: relative;
+.outside-elevator-closures {
display: flex;
+ flex: 1;
flex-direction: column;
- height: 100%;
- background-color: $warm-neutral-90;
.in-station-summary {
display: flex;
@@ -19,23 +17,7 @@
}
}
- 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;
- }
-
.outside-closure-list {
- position: relative;
height: 100%;
background-color: $warm-neutral-90;
@@ -67,7 +49,6 @@
transform: translateX(calc(-100% * var(--closure-list-offset)));
.closure-row {
- box-sizing: border-box;
width: 1080px;
padding: 0 48px;
@@ -129,16 +110,6 @@
align-self: center;
padding: 0 48px 20px;
}
-
- .paging-indicators {
- display: flex;
- align-items: center;
- margin-right: 66px;
-
- .paging-indicator:first-child:not(:only-child) {
- margin-right: 27px;
- }
- }
}
.paging-info-container,
diff --git a/assets/src/apps/v2/elevator.tsx b/assets/src/apps/v2/elevator.tsx
index cea5a1e47..b43342a35 100644
--- a/assets/src/apps/v2/elevator.tsx
+++ b/assets/src/apps/v2/elevator.tsx
@@ -14,14 +14,16 @@ 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 ElevatorClosures from "Components/v2/elevator/elevator_closures";
+import OutsideElevatorClosures from "Components/v2/elevator/outside_elevator_closures";
+import CurrentElevatorClosed from "Components/v2/elevator/current_elevator_closed";
import SimulationScreenPage from "Components/v2/simulation_screen_page";
import Footer from "Components/v2/elevator/footer";
import NormalHeader from "Components/v2/normal_header";
const TYPE_TO_COMPONENT = {
normal: NormalScreen,
- elevator_closures: ElevatorClosures,
+ outside_elevator_closures: OutsideElevatorClosures,
+ current_elevator_closed: CurrentElevatorClosed,
evergreen_content: EvergreenContent,
footer: Footer,
normal_header: NormalHeader,
diff --git a/assets/src/components/v2/elevator/current_elevator_closed.tsx b/assets/src/components/v2/elevator/current_elevator_closed.tsx
new file mode 100644
index 000000000..ad06cd3f6
--- /dev/null
+++ b/assets/src/components/v2/elevator/current_elevator_closed.tsx
@@ -0,0 +1,98 @@
+import React, { ComponentType } from "react";
+import cx from "classnames";
+import Arrow, { Direction } from "Components/v2/arrow";
+import makePersistent, {
+ WrappedComponentProps,
+} from "Components/v2/persistent_wrapper";
+import PagingIndicators from "Components/v2/elevator/paging_indicators";
+import { type Closure } from "Components/v2/elevator/types";
+import useClientPaging from "Hooks/v2/use_client_paging";
+import useTextResizer from "Hooks/v2/use_text_resizer";
+import CurrentLocationMarker from "Images/svgr_bundled/current-location-marker.svg";
+import CurrentLocationBackground from "Images/svgr_bundled/current-location-background.svg";
+import NoService from "Images/svgr_bundled/no-service-black.svg";
+import ElevatorWayfinding from "Images/svgr_bundled/elevator-wayfinding.svg";
+import IsaNegative from "Images/svgr_bundled/isa-negative.svg";
+
+type Coordinates = {
+ x: number;
+ y: number;
+};
+
+const PulsatingDot = ({ x, y }: Coordinates) => {
+ return (
+
+
+
+
+ );
+};
+
+interface Props extends WrappedComponentProps {
+ closure: Closure;
+ alternate_direction_text: string;
+ accessible_path_direction_arrow: Direction;
+ accessible_path_image_url: string | null;
+ accessible_path_image_here_coordinates: Coordinates;
+}
+
+const CurrentElevatorClosed = ({
+ alternate_direction_text: alternateDirectionText,
+ accessible_path_direction_arrow: accessiblePathDirectionArrow,
+ accessible_path_image_url: accessiblePathImageUrl,
+ accessible_path_image_here_coordinates: accessiblePathImageHereCoordinates,
+ onFinish,
+ lastUpdate,
+}: Props) => {
+ const numPages = accessiblePathImageUrl ? 2 : 1;
+ const pageIndex = useClientPaging({ numPages, onFinish, lastUpdate });
+ const { ref, size } = useTextResizer({
+ sizes: ["small", "medium", "large"],
+ maxHeight: 746,
+ resetDependencies: [alternateDirectionText],
+ });
+
+ return (
+
+
+
+
+
+
+
+
Closed
+
Until further notice
+
+
+
+
+ {pageIndex === 0 ? (
+
+ {alternateDirectionText}
+
+ ) : (
+
+
+
+
+ )}
+
+ {numPages === 2 && (
+
+ )}
+
+ );
+};
+
+export default makePersistent(
+ CurrentElevatorClosed as ComponentType,
+);
diff --git a/assets/src/components/v2/elevator/footer.tsx b/assets/src/components/v2/elevator/footer.tsx
index b9eeff968..a6d0675a3 100644
--- a/assets/src/components/v2/elevator/footer.tsx
+++ b/assets/src/components/v2/elevator/footer.tsx
@@ -1,8 +1,9 @@
import React from "react";
+import { classWithModifier } from "Util/util";
-const Footer = () => {
+const Footer = ({ variant }: { variant: string | null }) => {
return (
-
+
For more info and alternate paths: mbta.com/alerts/access or{" "}
617-222-2828
diff --git a/assets/src/components/v2/elevator/elevator_closures.tsx b/assets/src/components/v2/elevator/outside_elevator_closures.tsx
similarity index 66%
rename from assets/src/components/v2/elevator/elevator_closures.tsx
rename to assets/src/components/v2/elevator/outside_elevator_closures.tsx
index 4da4503e1..2618911ae 100644
--- a/assets/src/components/v2/elevator/elevator_closures.tsx
+++ b/assets/src/components/v2/elevator/outside_elevator_closures.tsx
@@ -1,28 +1,18 @@
import React, { ComponentType, useLayoutEffect, useRef, useState } from "react";
import cx from "classnames";
-import NormalService from "Images/svgr_bundled/normal-service.svg";
-import AccessibilityAlert from "Images/svgr_bundled/accessibility-alert.svg";
-import PagingDotUnselected from "Images/svgr_bundled/paging_dot_unselected.svg";
-import PagingDotSelected from "Images/svgr_bundled/paging_dot_selected.svg";
-import makePersistent, { WrappedComponentProps } from "../persistent_wrapper";
-import RoutePill, { routePillKey, type Pill } from "../departures/route_pill";
import _ from "lodash";
+import RoutePill, { routePillKey } from "Components/v2/departures/route_pill";
+import makePersistent, {
+ WrappedComponentProps,
+} from "Components/v2/persistent_wrapper";
+import PagingIndicators from "Components/v2/elevator/paging_indicators";
+import {
+ type StationWithClosures,
+ type Closure,
+} from "Components/v2/elevator/types";
import useClientPaging from "Hooks/v2/use_client_paging";
-
-type StationWithClosures = {
- id: string;
- name: string;
- route_icons: Pill[];
- closures: ElevatorClosure[];
-};
-
-type ElevatorClosure = {
- id: string;
- elevator_name: string;
- elevator_id: string;
- description: string;
- header_text: string;
-};
+import NormalService from "Images/svgr_bundled/normal-service.svg";
+import AccessibilityAlert from "Images/svgr_bundled/accessibility-alert.svg";
interface ClosureRowProps {
station: StationWithClosures;
@@ -54,19 +44,13 @@ const ClosureRow = ({ station }: ClosureRowProps) => {
);
};
-interface InStationSummaryProps {
- closures: ElevatorClosure[];
-}
-
-const InStationSummary = ({ closures }: InStationSummaryProps) => {
- const summaryText = closures.length
- ? ""
- : "All elevators at this station are currently working";
-
+const InStationSummary = () => {
return (
<>
-
{summaryText}
+
+ All elevators at this station are currently working
+
@@ -78,7 +62,6 @@ const InStationSummary = ({ closures }: InStationSummaryProps) => {
interface OutsideClosureListProps extends WrappedComponentProps {
stations: StationWithClosures[];
- lastUpdate: number | null;
}
const OutsideClosureList = ({
@@ -119,31 +102,6 @@ const OutsideClosureList = ({
setRowCounts(rowCounts);
}, [stations]);
- const getPagingIndicators = (num: number) => {
- const indicators: JSX.Element[] = [];
- for (let i = 0; i < num; i++) {
- const indicator =
- pageIndex === i ? (
-
- ) : (
-
- );
- indicators.push(indicator);
- }
-
- return indicators;
- };
-
return (
@@ -177,9 +135,7 @@ const OutsideClosureList = ({
+{numOffsetRows} more elevators
-
- {getPagingIndicators(numPages)}
-
+
)}
@@ -188,21 +144,20 @@ const OutsideClosureList = ({
interface Props extends WrappedComponentProps {
id: string;
- in_station_closures: ElevatorClosure[];
+ in_station_closures: Closure[];
other_stations_with_closures: StationWithClosures[];
}
-const ElevatorClosures: React.ComponentType
= ({
- other_stations_with_closures: otherStationsWithClosures,
- in_station_closures: inStationClosures,
+const OutsideElevatorClosures = ({
+ other_stations_with_closures: stations,
lastUpdate,
onFinish,
}: Props) => {
return (
-
-
+
+
@@ -211,5 +166,5 @@ const ElevatorClosures: React.ComponentType
= ({
};
export default makePersistent(
- ElevatorClosures as ComponentType,
+ OutsideElevatorClosures as ComponentType,
);
diff --git a/assets/src/components/v2/elevator/paging_indicators.tsx b/assets/src/components/v2/elevator/paging_indicators.tsx
new file mode 100644
index 000000000..406e68602
--- /dev/null
+++ b/assets/src/components/v2/elevator/paging_indicators.tsx
@@ -0,0 +1,35 @@
+import React from "react";
+import PagingDotUnselected from "Images/svgr_bundled/paging_dot_unselected.svg";
+import PagingDotSelected from "Images/svgr_bundled/paging_dot_selected.svg";
+
+interface PagingIndicatorsProps {
+ numPages: number;
+ pageIndex: number;
+}
+
+const PagingIndicators = ({ numPages, pageIndex }: PagingIndicatorsProps) => {
+ const indicators: JSX.Element[] = [];
+ for (let i = 0; i < numPages; i++) {
+ const indicator =
+ pageIndex === i ? (
+
+ ) : (
+
+ );
+ indicators.push(indicator);
+ }
+
+ return {indicators}
;
+};
+
+export default PagingIndicators;
diff --git a/assets/src/components/v2/elevator/types.ts b/assets/src/components/v2/elevator/types.ts
new file mode 100644
index 000000000..2d21013ba
--- /dev/null
+++ b/assets/src/components/v2/elevator/types.ts
@@ -0,0 +1,16 @@
+import { type Pill } from "Components/v2/departures/route_pill";
+
+export type StationWithClosures = {
+ id: string;
+ name: string;
+ route_icons: Pill[];
+ closures: Closure[];
+};
+
+export type Closure = {
+ id: string;
+ elevator_name: string;
+ elevator_id: string;
+ description: string;
+ header_text: string;
+};
diff --git a/assets/src/components/v2/normal_header.tsx b/assets/src/components/v2/normal_header.tsx
index da8397786..c0a69ec25 100644
--- a/assets/src/components/v2/normal_header.tsx
+++ b/assets/src/components/v2/normal_header.tsx
@@ -1,15 +1,9 @@
-import useTextResizer from "Hooks/v2/use_text_resizer";
import React, { forwardRef, ComponentType } from "react";
-import { getDatasetValue } from "Util/dataset";
import LiveDataSvg from "Images/svgr_bundled/live-data-small.svg";
-
-import {
- classWithModifier,
- classWithModifiers,
- formatTimeString,
- imagePath,
-} from "Util/util";
+import { getDatasetValue } from "Util/dataset";
+import { classWithModifiers, formatTimeString, imagePath } from "Util/util";
+import useTextResizer from "Hooks/v2/use_text_resizer";
enum Icon {
green_b = "green_b",
@@ -154,6 +148,7 @@ interface Props {
fullName?: boolean;
classModifiers?: string;
accentPattern?: string;
+ variant?: string | null;
}
const NormalHeader: ComponentType = ({
@@ -167,6 +162,7 @@ const NormalHeader: ComponentType = ({
fullName = false,
classModifiers,
accentPattern,
+ variant,
}) => {
const { ref: headerRef, size: headerSize } = useTextResizer({
sizes: Object.keys(TitleSize),
@@ -174,7 +170,9 @@ const NormalHeader: ComponentType = ({
resetDependencies: [text],
});
return (
-
+
{
if (modifiers.length === 0) {
return baseClass;
} else {
- return (
- `${baseClass} ` + modifiers.map((m) => `${baseClass}--${m}`).join(" ")
+ return cx(
+ baseClass,
+ ...modifiers.filter((m) => m).map((m) => `${baseClass}--${m}`),
);
}
};
diff --git a/assets/static/images/svgr_bundled/current-location-background.svg b/assets/static/images/svgr_bundled/current-location-background.svg
new file mode 100644
index 000000000..4c6354c40
--- /dev/null
+++ b/assets/static/images/svgr_bundled/current-location-background.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/static/images/svgr_bundled/current-location-marker.svg b/assets/static/images/svgr_bundled/current-location-marker.svg
new file mode 100644
index 000000000..430431a4f
--- /dev/null
+++ b/assets/static/images/svgr_bundled/current-location-marker.svg
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/assets/static/images/svgr_bundled/elevator-wayfinding.svg b/assets/static/images/svgr_bundled/elevator-wayfinding.svg
new file mode 100644
index 000000000..3f3c5d4e7
--- /dev/null
+++ b/assets/static/images/svgr_bundled/elevator-wayfinding.svg
@@ -0,0 +1,52 @@
+
\ No newline at end of file
diff --git a/assets/static/images/svgr_bundled/no-service-black.svg b/assets/static/images/svgr_bundled/no-service-black.svg
new file mode 100644
index 000000000..969faac38
--- /dev/null
+++ b/assets/static/images/svgr_bundled/no-service-black.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/lib/screens/v2/candidate_generator/elevator.ex b/lib/screens/v2/candidate_generator/elevator.ex
index 8de4a1e8c..01d6bcdaa 100644
--- a/lib/screens/v2/candidate_generator/elevator.ex
+++ b/lib/screens/v2/candidate_generator/elevator.ex
@@ -28,13 +28,15 @@ defmodule Screens.V2.CandidateGenerator.Elevator do
def candidate_instances(
config,
now \\ DateTime.utc_now(),
- elevator_closure_instances_fn \\ &ElevatorClosures.elevator_status_instances/1,
+ elevator_closure_instances_fn \\ &ElevatorClosures.elevator_status_instances/3,
evergreen_content_instances_fn \\ &Evergreen.evergreen_content_instances/2
) do
Enum.concat([
- [header_instance(config, now)],
- [footer_instance(config)],
- elevator_closure_instances_fn.(config),
+ elevator_closure_instances_fn.(
+ config,
+ header_instance(config, now),
+ footer_instance(config)
+ ),
evergreen_content_instances_fn.(config, now)
])
end
diff --git a/lib/screens/v2/candidate_generator/elevator/closures.ex b/lib/screens/v2/candidate_generator/elevator/closures.ex
index 127564cba..a3b28a5e7 100644
--- a/lib/screens/v2/candidate_generator/elevator/closures.ex
+++ b/lib/screens/v2/candidate_generator/elevator/closures.ex
@@ -6,7 +6,16 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
alias Screens.Alerts.{Alert, InformedEntity}
alias Screens.Routes.Route
alias Screens.Stops.Stop
- alias Screens.V2.WidgetInstance.ElevatorClosures
+ alias Screens.V2.WidgetInstance
+
+ alias Screens.V2.WidgetInstance.{
+ CurrentElevatorClosed,
+ Footer,
+ NormalHeader,
+ OutsideElevatorClosures
+ }
+
+ alias Screens.V2.WidgetInstance.Elevator.Closure
alias Screens.V2.WidgetInstance.Serializer.RoutePill
alias ScreensConfig.Screen
alias ScreensConfig.V2.Elevator
@@ -18,8 +27,13 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
@route injected(Route)
@stop injected(Stop)
- @spec elevator_status_instances(Screen.t()) :: list(ElevatorClosures.t())
- def elevator_status_instances(%Screen{app_params: %Elevator{elevator_id: elevator_id}}) do
+ @spec elevator_status_instances(Screen.t(), NormalHeader.t(), Footer.t()) ::
+ list(WidgetInstance.t())
+ def elevator_status_instances(
+ %Screen{app_params: %Elevator{elevator_id: elevator_id} = config},
+ header_instance,
+ footer_instance
+ ) do
with {:ok, %Stop{id: stop_id}} <- @facility.fetch_stop_for_facility(elevator_id),
{:ok, parent_station_map} <- @stop.fetch_parent_station_name_map(),
{:ok, alerts} <- @alert.fetch_elevator_alerts_with_facilities() do
@@ -29,13 +43,27 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
{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))
+
+ {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
+ }, nil}
+ else
+ {%CurrentElevatorClosed{closure: current_elevator_closure, app_params: config}, :closed}
+ end
+
[
- %ElevatorClosures{
- id: elevator_id,
- in_station_closures: Enum.map(in_station_alerts, &alert_to_elevator_closure/1),
- other_stations_with_closures:
- format_outside_closures(outside_alerts, parent_station_map, routes_map)
- }
+ %NormalHeader{header_instance | variant: header_footer_variant},
+ elevator_widget_instance,
+ %Footer{footer_instance | variant: header_footer_variant}
]
else
:error ->
@@ -106,7 +134,7 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
}) do
facility = Enum.find_value(entities, fn %{facility: facility} -> facility end)
- %ElevatorClosures.Closure{
+ %Closure{
id: id,
elevator_name: facility.name,
elevator_id: facility.id,
@@ -126,7 +154,7 @@ defmodule Screens.V2.CandidateGenerator.Elevator.Closures do
|> Map.fetch!(parent_station_id)
|> Enum.map(&RoutePill.serialize_icon/1)
- %ElevatorClosures.Station{
+ %OutsideElevatorClosures.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/blue_bikes.ex b/lib/screens/v2/widget_instance/blue_bikes.ex
index d46bb0cf3..017c514e0 100644
--- a/lib/screens/v2/widget_instance/blue_bikes.ex
+++ b/lib/screens/v2/widget_instance/blue_bikes.ex
@@ -4,8 +4,7 @@ defmodule Screens.V2.WidgetInstance.BlueBikes do
"""
alias Screens.BlueBikes
alias Screens.BlueBikes.StationStatus
- alias ScreensConfig.Screen
- alias ScreensConfig.V2.BlueBikes.Station
+ alias ScreensConfig.{Arrow, Screen}
alias ScreensConfig.V2.PreFare
@type t :: %__MODULE__{
@@ -24,7 +23,7 @@ defmodule Screens.V2.WidgetInstance.BlueBikes do
@type normal_station :: %{
status: :normal,
id: String.t(),
- arrow: Station.arrow(),
+ arrow: Arrow.t(),
walk_distance_minutes: non_neg_integer(),
walk_distance_feet: non_neg_integer(),
name: String.t(),
@@ -35,7 +34,7 @@ defmodule Screens.V2.WidgetInstance.BlueBikes do
@type special_station :: %{
status: :valet | :out_of_service,
id: String.t(),
- arrow: Station.arrow(),
+ arrow: Arrow.t(),
walk_distance_minutes: non_neg_integer(),
walk_distance_feet: non_neg_integer(),
name: String.t()
diff --git a/lib/screens/v2/widget_instance/current_elevator_closed.ex b/lib/screens/v2/widget_instance/current_elevator_closed.ex
new file mode 100644
index 000000000..8729c12dc
--- /dev/null
+++ b/lib/screens/v2/widget_instance/current_elevator_closed.ex
@@ -0,0 +1,51 @@
+defmodule Screens.V2.WidgetInstance.CurrentElevatorClosed do
+ @moduledoc false
+
+ alias Screens.Util.Assets
+ alias Screens.V2.WidgetInstance.Elevator.Closure
+ alias ScreensConfig.V2.Elevator
+
+ defstruct ~w[app_params closure]a
+
+ @type t :: %__MODULE__{
+ app_params: Elevator.t(),
+ closure: Closure.t()
+ }
+
+ def serialize(%__MODULE__{
+ app_params: %Elevator{
+ elevator_id: id,
+ alternate_direction_text: alternate_direction_text,
+ accessible_path_direction_arrow: accessible_path_direction_arrow,
+ accessible_path_image_url: accessible_path_image_url,
+ accessible_path_image_here_coordinates: accessible_path_image_here_coordinates
+ },
+ closure: closure
+ }),
+ do: %{
+ id: id,
+ closure: closure,
+ alternate_direction_text: alternate_direction_text,
+ accessible_path_direction_arrow: accessible_path_direction_arrow,
+ accessible_path_image_url:
+ if(is_nil(accessible_path_image_url),
+ do: nil,
+ else: Assets.s3_asset_url(accessible_path_image_url)
+ ),
+ accessible_path_image_here_coordinates: accessible_path_image_here_coordinates
+ }
+
+ defimpl Screens.V2.WidgetInstance do
+ alias Screens.V2.WidgetInstance.CurrentElevatorClosed
+
+ def priority(_instance), do: [1]
+ def serialize(instance), do: CurrentElevatorClosed.serialize(instance)
+ def slot_names(_instance), do: [:main_content]
+ def widget_type(_instance), do: :current_elevator_closed
+ 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.CurrentElevatorClosedView
+ end
+end
diff --git a/lib/screens/v2/widget_instance/elevator/closure.ex b/lib/screens/v2/widget_instance/elevator/closure.ex
new file mode 100644
index 000000000..88990fe1d
--- /dev/null
+++ b/lib/screens/v2/widget_instance/elevator/closure.ex
@@ -0,0 +1,17 @@
+defmodule Screens.V2.WidgetInstance.Elevator.Closure do
+ @moduledoc """
+ Represents a serializable closure to be displayed on elevator widgets.
+ """
+
+ @derive Jason.Encoder
+
+ defstruct ~w[id elevator_name elevator_id description header_text]a
+
+ @type t :: %__MODULE__{
+ id: String.t(),
+ elevator_name: String.t(),
+ elevator_id: String.t(),
+ description: String.t(),
+ header_text: String.t()
+ }
+end
diff --git a/lib/screens/v2/widget_instance/footer.ex b/lib/screens/v2/widget_instance/footer.ex
index 9a5f54904..a273c228e 100644
--- a/lib/screens/v2/widget_instance/footer.ex
+++ b/lib/screens/v2/widget_instance/footer.ex
@@ -3,16 +3,23 @@ defmodule Screens.V2.WidgetInstance.Footer do
alias ScreensConfig.Screen
- defstruct screen: nil
+ defstruct screen: nil, variant: nil
@type t :: %__MODULE__{
- screen: Screen.t()
+ screen: Screen.t(),
+ variant: atom() | nil
}
+ def serialize(%__MODULE__{variant: variant}) do
+ %{variant: variant}
+ end
+
defimpl Screens.V2.WidgetInstance do
+ alias Screens.V2.WidgetInstance.Footer
+
def priority(_instance), do: [1]
- def serialize(_instance), do: %{}
+ def serialize(instance), do: Footer.serialize(instance)
def slot_names(_instance), do: [:footer]
diff --git a/lib/screens/v2/widget_instance/normal_header.ex b/lib/screens/v2/widget_instance/normal_header.ex
index 90ba5ad88..ecdcfe9d5 100644
--- a/lib/screens/v2/widget_instance/normal_header.ex
+++ b/lib/screens/v2/widget_instance/normal_header.ex
@@ -8,14 +8,16 @@ defmodule Screens.V2.WidgetInstance.NormalHeader do
defstruct screen: nil,
icon: nil,
text: nil,
- time: nil
+ time: nil,
+ variant: nil
@type icon :: :logo | :green_b | :green_c | :green_d | :green_e
@type t :: %__MODULE__{
screen: ScreensConfig.Screen.t(),
icon: icon | nil,
text: String.t(),
- time: DateTime.t()
+ time: DateTime.t(),
+ variant: atom() | nil
}
# Mercury adds their own time so we omit the time in the response.
@@ -24,8 +26,14 @@ defmodule Screens.V2.WidgetInstance.NormalHeader do
%{icon: icon, text: text, show_to: showing_destination?(t)}
end
- def serialize(%__MODULE__{icon: icon, text: text, time: time} = t) do
- %{icon: icon, text: text, time: DateTime.to_iso8601(time), show_to: showing_destination?(t)}
+ def serialize(%__MODULE__{icon: icon, text: text, time: time, variant: variant} = t) do
+ %{
+ icon: icon,
+ text: text,
+ time: DateTime.to_iso8601(time),
+ show_to: showing_destination?(t),
+ variant: variant
+ }
end
def slot_names(%__MODULE__{screen: %Screen{app_id: :dup_v2}}) do
diff --git a/lib/screens/v2/widget_instance/elevator_closures.ex b/lib/screens/v2/widget_instance/outside_elevator_closures.ex
similarity index 55%
rename from lib/screens/v2/widget_instance/elevator_closures.ex
rename to lib/screens/v2/widget_instance/outside_elevator_closures.ex
index a819ca248..bcc2f12e1 100644
--- a/lib/screens/v2/widget_instance/elevator_closures.ex
+++ b/lib/screens/v2/widget_instance/outside_elevator_closures.ex
@@ -1,13 +1,15 @@
-defmodule Screens.V2.WidgetInstance.ElevatorClosures do
+defmodule Screens.V2.WidgetInstance.OutsideElevatorClosures do
@moduledoc false
alias Screens.Stops.Stop
+ alias Screens.V2.WidgetInstance.Elevator.Closure
+ alias ScreensConfig.V2.Elevator
- defstruct ~w[id in_station_closures other_stations_with_closures]a
+ defstruct ~w[app_params in_station_closures other_stations_with_closures]a
@type t :: %__MODULE__{
- id: String.t(),
- in_station_closures: list(__MODULE__.Closure.t()),
+ app_params: Elevator.t(),
+ in_station_closures: list(Closure.t()),
other_stations_with_closures: list(__MODULE__.Station.t())
}
@@ -15,7 +17,7 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosures do
@moduledoc false
alias Screens.Routes.Route
- alias Screens.V2.WidgetInstance.ElevatorClosures.Closure
+ alias Screens.V2.WidgetInstance.Elevator.Closure
@derive Jason.Encoder
@@ -29,24 +31,8 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosures do
}
end
- defmodule Closure do
- @moduledoc false
-
- @derive Jason.Encoder
-
- defstruct ~w[id elevator_name elevator_id description header_text]a
-
- @type t :: %__MODULE__{
- id: String.t(),
- elevator_name: String.t(),
- elevator_id: String.t(),
- description: String.t(),
- header_text: String.t()
- }
- end
-
def serialize(%__MODULE__{
- id: id,
+ app_params: %Elevator{elevator_id: id},
in_station_closures: in_station_closures,
other_stations_with_closures: other_stations_with_closures
}),
@@ -57,16 +43,16 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosures do
}
defimpl Screens.V2.WidgetInstance do
- alias Screens.V2.WidgetInstance.ElevatorClosures
+ alias Screens.V2.WidgetInstance.OutsideElevatorClosures
def priority(_instance), do: [1]
- def serialize(instance), do: ElevatorClosures.serialize(instance)
+ def serialize(instance), do: OutsideElevatorClosures.serialize(instance)
def slot_names(_instance), do: [:main_content]
- def widget_type(_instance), do: :elevator_closures
+ def widget_type(_instance), do: :outside_elevator_closures
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.ElevatorClosuresView
+ def audio_view(_instance), do: ScreensWeb.V2.Audio.OutsideElevatorClosuresView
end
end
diff --git a/lib/screens_web/views/v2/audio/elevator_closures_view.ex b/lib/screens_web/views/v2/audio/current_elevator_closed_view.ex
similarity index 57%
rename from lib/screens_web/views/v2/audio/elevator_closures_view.ex
rename to lib/screens_web/views/v2/audio/current_elevator_closed_view.ex
index 7bd732227..8060c80da 100644
--- a/lib/screens_web/views/v2/audio/elevator_closures_view.ex
+++ b/lib/screens_web/views/v2/audio/current_elevator_closed_view.ex
@@ -1,4 +1,4 @@
-defmodule ScreensWeb.V2.Audio.ElevatorClosuresView do
+defmodule ScreensWeb.V2.Audio.CurrentElevatorClosedView do
use ScreensWeb, :view
def render("_widget.ssml", _) do
diff --git a/lib/screens_web/views/v2/audio/outside_elevator_closures_view.ex b/lib/screens_web/views/v2/audio/outside_elevator_closures_view.ex
new file mode 100644
index 000000000..bfee0f336
--- /dev/null
+++ b/lib/screens_web/views/v2/audio/outside_elevator_closures_view.ex
@@ -0,0 +1,7 @@
+defmodule ScreensWeb.V2.Audio.OutsideElevatorClosuresView do
+ use ScreensWeb, :view
+
+ def render("_widget.ssml", _) do
+ ~E""
+ end
+end
diff --git a/mix.exs b/mix.exs
index 496808d1b..c6818aba8 100644
--- a/mix.exs
+++ b/mix.exs
@@ -94,7 +94,7 @@ defmodule Screens.MixProject do
{:telemetry_metrics, "~> 0.4"},
{:screens_config,
git: "https://github.com/mbta/screens-config-lib.git",
- ref: "c0db78ecd43c633a55a1f24b268ae7b8a5214748"},
+ ref: "bbc9575e375b28b0489732eefa66c2ca3f100d0e"},
{:nebulex, "~> 2.6"},
{:remote_ip, "~> 1.2"},
{:hackney_telemetry, "~> 0.2.0"},
diff --git a/mix.lock b/mix.lock
index e27785181..68b6eb004 100644
--- a/mix.lock
+++ b/mix.lock
@@ -62,7 +62,7 @@
"recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"},
"remote_ip": {:hex, :remote_ip, "1.2.0", "fb078e12a44414f4cef5a75963c33008fe169b806572ccd17257c208a7bc760f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2ff91de19c48149ce19ed230a81d377186e4412552a597d6a5137373e5877cb7"},
"retry": {:hex, :retry, "0.18.0", "dc58ebe22c95aa00bc2459f9e0c5400e6005541cf8539925af0aa027dc860543", [:mix], [], "hexpm", "9483959cc7bf69c9e576d9dfb2b678b71c045d3e6f39ab7c9aa1489df4492d73"},
- "screens_config": {:git, "https://github.com/mbta/screens-config-lib.git", "c0db78ecd43c633a55a1f24b268ae7b8a5214748", [ref: "c0db78ecd43c633a55a1f24b268ae7b8a5214748"]},
+ "screens_config": {:git, "https://github.com/mbta/screens-config-lib.git", "bbc9575e375b28b0489732eefa66c2ca3f100d0e", [ref: "bbc9575e375b28b0489732eefa66c2ca3f100d0e"]},
"sentry": {:hex, :sentry, "10.7.1", "33392222d80ccff99c503f972998d2858b4c1e5aca2219a34269b68dacba8e7d", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "56291312397bf2b6afab6cf4f7aa1f27413b0eb2ceeb63b8aab2d7658aaea882"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"stream_data": {:hex, :stream_data, "1.1.2", "05499eaec0443349ff877aaabc6e194e82bda6799b9ce6aaa1aadac15a9fdb4d", [:mix], [], "hexpm", "129558d2c77cbc1eb2f4747acbbea79e181a5da51108457000020a906813a1a9"},
diff --git a/test/screens/v2/candidate_generator/elevator/closures_test.exs b/test/screens/v2/candidate_generator/elevator/closures_test.exs
index 9dd6582ed..31aa6f5dc 100644
--- a/test/screens/v2/candidate_generator/elevator/closures_test.exs
+++ b/test/screens/v2/candidate_generator/elevator/closures_test.exs
@@ -1,10 +1,19 @@
defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
use ExUnit.Case, async: true
+ alias Screens.V2.WidgetInstance.Elevator.Closure
alias Screens.Alerts.Alert
alias Screens.Routes.Route
alias Screens.Stops.Stop
alias Screens.V2.CandidateGenerator.Elevator.Closures, as: ElevatorClosures
+
+ alias Screens.V2.WidgetInstance.{
+ CurrentElevatorClosed,
+ Footer,
+ NormalHeader,
+ OutsideElevatorClosures
+ }
+
alias ScreensConfig.Screen
alias ScreensConfig.V2.Elevator
@@ -17,8 +26,31 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
@route injected(Route)
@stop injected(Stop)
- describe "elevator_status_instances/1" do
- test "Only returns alerts with effect of :elevator_closure" do
+ describe "elevator_status_instances/3" do
+ setup do
+ config = %Elevator{
+ elevator_id: "111",
+ accessible_path_direction_arrow: :n,
+ alternate_direction_text: "Test"
+ }
+
+ %{
+ config: config,
+ header_instance: %NormalHeader{
+ screen: config,
+ icon: nil,
+ text: "Elevator 1",
+ time: ~U[2020-04-06T10:00:00Z]
+ },
+ footer_instance: %Footer{screen: config}
+ }
+ end
+
+ test "Only returns alerts with effect of :elevator_closure", %{
+ config: config,
+ header_instance: header_instance,
+ footer_instance: footer_instance
+ } do
expect(@facility, :fetch_stop_for_facility, fn "111" -> {:ok, %Stop{id: "place-test"}} end)
expect(@stop, :fetch_parent_station_name_map, fn ->
@@ -50,8 +82,9 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
end)
[
- %Screens.V2.WidgetInstance.ElevatorClosures{
- id: "111",
+ ^header_instance,
+ %OutsideElevatorClosures{
+ app_params: ^config,
in_station_closures: [
%{
id: "1",
@@ -62,14 +95,21 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
}
],
other_stations_with_closures: []
- }
+ },
+ ^footer_instance
] =
ElevatorClosures.elevator_status_instances(
- struct(Screen, app_id: :elevator_v2, app_params: %Elevator{elevator_id: "111"})
+ struct(Screen, app_id: :elevator_v2, app_params: config),
+ header_instance,
+ footer_instance
)
end
- test "Groups outside closures by station" do
+ test "Groups outside closures by station", %{
+ config: config,
+ header_instance: header_instance,
+ footer_instance: footer_instance
+ } do
expect(@facility, :fetch_stop_for_facility, fn "111" -> {:ok, %Stop{id: "place-test"}} end)
expect(@stop, :fetch_parent_station_name_map, fn ->
@@ -106,8 +146,9 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
end)
[
- %Screens.V2.WidgetInstance.ElevatorClosures{
- id: "111",
+ ^header_instance,
+ %OutsideElevatorClosures{
+ app_params: ^config,
in_station_closures: [],
other_stations_with_closures: [
%{
@@ -132,14 +173,21 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
]
}
]
- }
+ },
+ ^footer_instance
] =
ElevatorClosures.elevator_status_instances(
- struct(Screen, app_id: :elevator_v2, app_params: %Elevator{elevator_id: "111"})
+ struct(Screen, app_id: :elevator_v2, app_params: config),
+ header_instance,
+ footer_instance
)
end
- test "Filters alerts with no facilities or more than one facility" do
+ test "Filters alerts with no facilities or more than one facility", %{
+ config: config,
+ header_instance: header_instance,
+ footer_instance: footer_instance
+ } do
expect(@facility, :fetch_stop_for_facility, fn "111" -> {:ok, %Stop{id: "place-test"}} end)
expect(@stop, :fetch_parent_station_name_map, fn ->
@@ -171,18 +219,85 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
end)
[
- %Screens.V2.WidgetInstance.ElevatorClosures{
- id: "111",
+ ^header_instance,
+ %OutsideElevatorClosures{
+ app_params: ^config,
in_station_closures: [],
other_stations_with_closures: []
- }
+ },
+ ^footer_instance
+ ] =
+ ElevatorClosures.elevator_status_instances(
+ struct(Screen, app_id: :elevator_v2, app_params: config),
+ header_instance,
+ footer_instance
+ )
+ end
+
+ test "Returns CurrentElevatorClosed if configured elevator is closed", %{
+ config: config,
+ header_instance: header_instance,
+ footer_instance: footer_instance
+ } do
+ expect(@facility, :fetch_stop_for_facility, fn "111" -> {:ok, %Stop{id: "place-test"}} end)
+
+ expect(@stop, :fetch_parent_station_name_map, fn ->
+ {:ok, %{"place-test" => "Place Test"}}
+ end)
+
+ expect(@route, :fetch, fn %{stop_id: "place-test"} ->
+ {:ok, [%Route{id: "Red", type: :subway}]}
+ end)
+
+ expect(@alert, :fetch_elevator_alerts_with_facilities, fn ->
+ alerts = [
+ struct(Alert,
+ id: "1",
+ effect: :elevator_closure,
+ informed_entities: [
+ %{stop: "place-test", facility: %{name: "Test", id: "111"}}
+ ]
+ ),
+ struct(Alert,
+ effect: :detour,
+ informed_entities: [
+ %{stop: "place-test", facility: %{name: "Test 2", id: "facility-test2"}}
+ ]
+ )
+ ]
+
+ {:ok, alerts}
+ end)
+
+ closed_header_instance = %{header_instance | variant: :closed}
+ closed_footer_instance = %{footer_instance | variant: :closed}
+
+ [
+ ^closed_header_instance,
+ %CurrentElevatorClosed{
+ app_params: ^config,
+ closure: %Closure{
+ id: "1",
+ elevator_name: "Test",
+ elevator_id: "111",
+ description: nil,
+ header_text: nil
+ }
+ },
+ ^closed_footer_instance
] =
ElevatorClosures.elevator_status_instances(
- struct(Screen, app_id: :elevator_v2, app_params: %Elevator{elevator_id: "111"})
+ struct(Screen, app_id: :elevator_v2, app_params: config),
+ header_instance,
+ footer_instance
)
end
- test "Return empty routes on API error" do
+ test "Return empty routes on API error", %{
+ config: config,
+ header_instance: header_instance,
+ footer_instance: footer_instance
+ } do
expect(@facility, :fetch_stop_for_facility, fn "111" -> {:ok, %Stop{id: "place-test"}} end)
expect(@stop, :fetch_parent_station_name_map, fn ->
@@ -208,8 +323,9 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
end)
[
- %Screens.V2.WidgetInstance.ElevatorClosures{
- id: "111",
+ ^header_instance,
+ %OutsideElevatorClosures{
+ app_params: ^config,
in_station_closures: [
%{
id: "1",
@@ -220,10 +336,13 @@ defmodule Screens.V2.CandidateGenerator.Elevator.ClosuresTest do
}
],
other_stations_with_closures: []
- }
+ },
+ ^footer_instance
] =
ElevatorClosures.elevator_status_instances(
- struct(Screen, app_id: :elevator_v2, app_params: %Elevator{elevator_id: "111"})
+ struct(Screen, app_id: :elevator_v2, app_params: config),
+ header_instance,
+ footer_instance
)
end
end
diff --git a/test/screens/v2/candidate_generator/elevator_test.exs b/test/screens/v2/candidate_generator/elevator_test.exs
index 979843fcf..555459187 100644
--- a/test/screens/v2/candidate_generator/elevator_test.exs
+++ b/test/screens/v2/candidate_generator/elevator_test.exs
@@ -9,7 +9,9 @@ defmodule Screens.V2.CandidateGenerator.ElevatorTest do
config = %Screen{
app_id: :elevator_v2,
app_params: %V2.Elevator{
- elevator_id: "1"
+ elevator_id: "1",
+ alternate_direction_text: "Test",
+ accessible_path_direction_arrow: :n
},
device_id: "TEST",
name: "TEST",
@@ -31,8 +33,6 @@ defmodule Screens.V2.CandidateGenerator.ElevatorTest do
describe "candidate_instances/4" do
test "returns expected header and footer", %{config: config} do
now = ~U[2020-04-06T10:00:00Z]
- elevator_closure_instances_fn = fn _ -> [] end
- evergreen_content_instances_fn = fn _, _ -> [] end
expected_header = %NormalHeader{
screen: config,
@@ -42,6 +42,8 @@ defmodule Screens.V2.CandidateGenerator.ElevatorTest do
}
expected_footer = %Footer{screen: config}
+ elevator_closure_instances_fn = fn _, _, _ -> [expected_header, expected_footer] end
+ evergreen_content_instances_fn = fn _, _ -> [] end
actual_instances =
Elevator.candidate_instances(
diff --git a/test/screens/v2/widget_instance/current_elevator_closed_test.exs b/test/screens/v2/widget_instance/current_elevator_closed_test.exs
new file mode 100644
index 000000000..bbba11a43
--- /dev/null
+++ b/test/screens/v2/widget_instance/current_elevator_closed_test.exs
@@ -0,0 +1,85 @@
+defmodule Screens.V2.WidgetInstance.CurrentElevatorClosedTest do
+ use ExUnit.Case, async: true
+
+ alias Screens.V2.WidgetInstance
+ alias Screens.V2.WidgetInstance.CurrentElevatorClosed
+ alias Screens.V2.WidgetInstance.Elevator.Closure
+ alias ScreensConfig.V2.Elevator
+
+ setup do
+ %{
+ instance: %CurrentElevatorClosed{
+ app_params:
+ struct(Elevator,
+ elevator_id: "111",
+ alternate_direction_text: "Test",
+ accessible_path_direction_arrow: :n
+ ),
+ closure: %Closure{
+ description: "Test Alert Description",
+ elevator_name: "Test Elevator",
+ elevator_id: "111",
+ id: "1",
+ header_text: "Test Alert Header"
+ }
+ }
+ }
+ end
+
+ describe "priority/1" do
+ test "returns 1", %{instance: instance} do
+ assert [1] == WidgetInstance.priority(instance)
+ end
+ end
+
+ describe "serialize/1" do
+ test "returns map with id, closure, and alternate direction info", %{instance: instance} do
+ assert %{
+ closure: instance.closure,
+ accessible_path_direction_arrow:
+ instance.app_params.accessible_path_direction_arrow,
+ accessible_path_image_here_coordinates:
+ instance.app_params.accessible_path_image_here_coordinates,
+ accessible_path_image_url: instance.app_params.accessible_path_image_url,
+ alternate_direction_text: instance.app_params.alternate_direction_text,
+ id: instance.app_params.elevator_id
+ } == WidgetInstance.serialize(instance)
+ end
+ end
+
+ describe "slot_names/1" do
+ test "returns main_content", %{instance: instance} do
+ assert [:main_content] == WidgetInstance.slot_names(instance)
+ end
+ end
+
+ describe "widget_type/1" do
+ test "returns current_elevator_closed", %{instance: instance} do
+ assert :current_elevator_closed == WidgetInstance.widget_type(instance)
+ end
+ end
+
+ describe "audio_serialize/1" do
+ test "returns empty map", %{instance: instance} do
+ assert %{} == WidgetInstance.audio_serialize(instance)
+ end
+ end
+
+ describe "audio_sort_key/1" do
+ test "returns [0]", %{instance: instance} do
+ assert [0] == WidgetInstance.audio_sort_key(instance)
+ end
+ end
+
+ describe "audio_valid_candidate?/1" do
+ test "returns false", %{instance: instance} do
+ refute WidgetInstance.audio_valid_candidate?(instance)
+ end
+ end
+
+ describe "audio_view/1" do
+ test "returns CurrentElevatorClosedView", %{instance: instance} do
+ assert ScreensWeb.V2.Audio.CurrentElevatorClosedView == WidgetInstance.audio_view(instance)
+ end
+ end
+end
diff --git a/test/screens/v2/widget_instance/normal_header_test.exs b/test/screens/v2/widget_instance/normal_header_test.exs
index 1e828eaff..6fbc15408 100644
--- a/test/screens/v2/widget_instance/normal_header_test.exs
+++ b/test/screens/v2/widget_instance/normal_header_test.exs
@@ -52,7 +52,8 @@ defmodule Screens.V2.WidgetInstance.NormalHeaderTest do
icon: :logo,
text: "Ruggles",
time: "2021-03-04T11:00:00Z",
- show_to: false
+ show_to: false,
+ variant: nil
} == WidgetInstance.serialize(instance)
end
end
diff --git a/test/screens/v2/widget_instance/elevator_closures_test.exs b/test/screens/v2/widget_instance/outside_elevator_closures_test.exs
similarity index 60%
rename from test/screens/v2/widget_instance/elevator_closures_test.exs
rename to test/screens/v2/widget_instance/outside_elevator_closures_test.exs
index 553ea625a..ee8397206 100644
--- a/test/screens/v2/widget_instance/elevator_closures_test.exs
+++ b/test/screens/v2/widget_instance/outside_elevator_closures_test.exs
@@ -1,15 +1,22 @@
-defmodule Screens.V2.WidgetInstance.ElevatorClosuresTest do
+defmodule Screens.V2.WidgetInstance.OutsideElevatorClosuresTest do
use ExUnit.Case, async: true
alias Screens.V2.WidgetInstance
- alias Screens.V2.WidgetInstance.ElevatorClosures
+ alias Screens.V2.WidgetInstance.Elevator.Closure
+ alias Screens.V2.WidgetInstance.OutsideElevatorClosures
+ alias ScreensConfig.V2.Elevator
setup do
%{
- instance: %ElevatorClosures{
- id: "111",
+ instance: %OutsideElevatorClosures{
+ app_params:
+ struct(Elevator,
+ elevator_id: "1",
+ alternate_direction_text: "Test",
+ accessible_path_direction_arrow: :n
+ ),
in_station_closures: [
- %ElevatorClosures.Closure{
+ %Closure{
description: "Test Alert Description",
elevator_name: "Test Elevator",
elevator_id: "111",
@@ -18,11 +25,11 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosuresTest do
}
],
other_stations_with_closures: [
- %ElevatorClosures.Station{
+ %OutsideElevatorClosures.Station{
name: "Forest Hills",
route_icons: ["Orange"],
closures: [
- %ElevatorClosures.Closure{
+ %Closure{
description: "FH Alert Description",
elevator_name: "FH Elevator",
elevator_id: "222",
@@ -44,7 +51,11 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosuresTest do
describe "serialize/1" do
test "returns map with id and closures", %{instance: instance} do
- assert Map.from_struct(instance) == WidgetInstance.serialize(instance)
+ assert %{
+ in_station_closures: instance.in_station_closures,
+ other_stations_with_closures: instance.other_stations_with_closures,
+ id: instance.app_params.elevator_id
+ } == WidgetInstance.serialize(instance)
end
end
@@ -55,8 +66,8 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosuresTest do
end
describe "widget_type/1" do
- test "returns elevator_closures", %{instance: instance} do
- assert :elevator_closures == WidgetInstance.widget_type(instance)
+ test "returns outside_elevator_closures", %{instance: instance} do
+ assert :outside_elevator_closures == WidgetInstance.widget_type(instance)
end
end
@@ -79,8 +90,9 @@ defmodule Screens.V2.WidgetInstance.ElevatorClosuresTest do
end
describe "audio_view/1" do
- test "returns ElevatorClosuresView", %{instance: instance} do
- assert ScreensWeb.V2.Audio.ElevatorClosuresView == WidgetInstance.audio_view(instance)
+ test "returns OutsideElevatorClosuresView", %{instance: instance} do
+ assert ScreensWeb.V2.Audio.OutsideElevatorClosuresView ==
+ WidgetInstance.audio_view(instance)
end
end
end