diff --git a/assets/css/v2/pre_fare/simulation.scss b/assets/css/v2/pre_fare/simulation.scss index 8ddc30582..fb7b6a42c 100644 --- a/assets/css/v2/pre_fare/simulation.scss +++ b/assets/css/v2/pre_fare/simulation.scss @@ -5,7 +5,7 @@ } .simulation-screen-scrolling-container { - scrollbar-color: #607180 #2E3F4D; + scrollbar-color: #607180 #2e3f4d; &::-webkit-scrollbar { width: 12px; @@ -13,12 +13,12 @@ &::-webkit-scrollbar-thumb { background-color: #607180; border-radius: 12px; - border: 2px solid #2E3F4D; + border: 2px solid #2e3f4d; } &::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); border-radius: 12px; - background-color: #2E3F4D; + background-color: #2e3f4d; } } @@ -26,99 +26,95 @@ display: flex; overflow-y: hidden; overflow-x: auto; - padding-bottom: 20px; + margin-bottom: 20px; + height: 449px; .simulation__full-page { - height: 344px; - width: 387px; - margin-right: 24px; + max-height: 407px; + max-width: 388px; + margin: 16px; z-index: 999; - box-shadow: 0px 0px 32px 0px #00000040; - & > * { - transform-origin: top left; - transform: scale(17.92%); + .simulation__title { + font-family: Inter; + font-size: 16px; + font-weight: 700; + line-height: 24px; + color: #f8f9fa; + margin-bottom: 10px; } - } - - .simulation__flex-zone { - background: #2e3f4d; - display: flex; - margin: auto 2px auto 0; - height: 160px; - border-radius: 0 8px 8px 0; - position: relative; - &:before { - content: ""; - position: absolute; - right: 100%; - // NO HEIGHT - border-top: 80px solid transparent; - border-right: 100px solid #2e3f4d; - border-bottom: 80px solid transparent; + & > *:not(.simulation__title) { + transform-origin: top left; + transform: scale(17.92%); } } - .simulation__flex-zone-widget { - width: 256px; - height: 144px; - margin-top: auto; - margin-bottom: auto; + .simulation__left-screen { + height: 375px; + margin: 32px 16px 16px 16px; - .alert-container--urgent { - background-color: unset; - } + .simulation__left-screen-widget-container { + display: flex; - &:last-child { - margin-right: 8px; + .simulation__left-screen-widget { + width: 194px; + margin-right: 24px; + & > * { + height: 1720px; + width: 1080px; + transform-origin: top left; + transform: scale(17.92%); + overflow: hidden; + } + } } - &:not(:last-child) { - margin-right: 24px; + .simulation__title { + font-family: Inter; + font-size: 16px; + font-weight: 400; + line-height: 24px; + color: #f8f9fa; + margin-bottom: 10px; } + } - .flex-one-large, - .flex-two-medium { - transform-origin: top left; - transform: scale(25%); - - .flex-one-large__large { - .evergreen-content-image__container, - .evergreen-content-image__image { - max-width: 1024px; - max-height: 576px; - } - } - - .flex-two-medium__left, - .flex-two-medium__right { - .evergreen-content-image__container, - .evergreen-content-image__image { - max-width: 480px; - max-height: 580px; - } - } + .simulation__right-screen { + height: 375px; + margin: 128px 16px 16px 16px; - & > * { - position: unset; + .simulation__right-screen-widget-container { + display: flex; - // Pre-Fare flex-zones are a little weird. - // For some reason, some widgets have padding or margin that throw off the positioning in the sim. - // Removing margin and padding in the widget fixes it. + .simulation__right-screen-widget { + width: 194px; + margin-right: 24px; & > * { - margin: 0; - padding: 0; + height: 1720px; + width: 1080px; + transform-origin: top left; + transform: scale(17.92%); + overflow: hidden; } } } - .flex-two-medium { - display: flex; - - .flex-two-medium__left { - margin-right: 40px; - } + .simulation__title { + font-family: Inter; + font-size: 16px; + font-weight: 400; + line-height: 24px; + color: #f8f9fa; + margin-bottom: 10px; } } + + .divider:after { + content: ""; + position: absolute; + border-left: 1px solid #1e2933; + top: 48px; + height: 343px; + } } diff --git a/assets/src/apps/v2/pre_fare.tsx b/assets/src/apps/v2/pre_fare.tsx index 65ca709ab..a3333055a 100644 --- a/assets/src/apps/v2/pre_fare.tsx +++ b/assets/src/apps/v2/pre_fare.tsx @@ -47,7 +47,7 @@ import ReconstructedTakeover from "Components/v2/reconstructed_takeover"; import CRDepartures from "Components/v2/cr_departures/cr_departures"; import OvernightCRDepartures from "Components/v2/cr_departures/overnight_cr_departures"; import MultiScreenPage from "Components/v2/multi_screen_page"; -import SimulationScreenPage from "Components/v2/simulation_screen_page"; +import SimulationScreenPage from "Components/v2/pre_fare/simulation_screen_page"; import SurgeBodyRight from "Components/v2/pre_fare/surge_body_right"; import ShuttleBusInfo from "Components/v2/shuttle_bus_info"; import BlueBikes from "Components/v2/blue_bikes"; diff --git a/assets/src/components/v2/pre_fare/simulation_screen_container.tsx b/assets/src/components/v2/pre_fare/simulation_screen_container.tsx new file mode 100644 index 000000000..1869cbaeb --- /dev/null +++ b/assets/src/components/v2/pre_fare/simulation_screen_container.tsx @@ -0,0 +1,108 @@ +import React, { ComponentType, useContext } from "react"; +import { + LastFetchContext, + ResponseMapperContext, +} from "Components/v2/screen_container"; +import Widget, { WidgetData } from "Components/v2/widget"; +import { + ApiResponse, + useSimulationApiResponse, +} from "Hooks/v2/use_api_response"; +import WidgetTreeErrorBoundary from "Components/v2/widget_tree_error_boundary"; + +interface SimulationScreenLayoutProps { + apiResponse: ApiResponse; +} + +const SimulationScreenLayout: ComponentType = ({ + apiResponse, +}) => { + const responseMapper = useContext(ResponseMapperContext); + const data = responseMapper(apiResponse); + const { fullPage, flexZone } = data; + let leftScreenPages: WidgetData[] = []; + let rightScreenPages: WidgetData[] = []; + if (flexZone) { + leftScreenPages = flexZone.filter( + (widget: WidgetData) => widget.type === "body_left_flex" + ); + rightScreenPages = flexZone.filter( + (widget: WidgetData) => !leftScreenPages.includes(widget) + ); + } + + return ( +
+
+ {apiResponse && ( +
+
Live view
+ + + +
+ )} + {flexZone &&
} + {leftScreenPages && leftScreenPages.length > 0 && ( +
+
+ Left panel ({leftScreenPages.length}) +
+
+ {leftScreenPages.map( + (flexZonePage: WidgetData, index: number) => { + return ( +
+ +
+ ); + } + )} +
+
+ )} + {rightScreenPages && rightScreenPages.length > 0 && ( +
+
+ Flex zone ({rightScreenPages.length}) +
+
+ {rightScreenPages.map( + (flexZonePage: WidgetData, index: number) => { + return ( +
+ +
+ ); + } + )} +
+
+ )} +
+
+ ); +}; + +const SimulationScreenContainer = ({ + id, +}: { + id: string; + opts?: { [key: string]: any }; +}) => { + const { apiResponse, lastSuccess } = useSimulationApiResponse({ id }); + + return ( + + + + ); +}; + +export default SimulationScreenContainer; diff --git a/assets/src/components/v2/pre_fare/simulation_screen_page.tsx b/assets/src/components/v2/pre_fare/simulation_screen_page.tsx new file mode 100644 index 000000000..1fca8bde4 --- /dev/null +++ b/assets/src/components/v2/pre_fare/simulation_screen_page.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import { useParams } from "react-router-dom"; +import SimulationScreenContainer from "Components/v2/pre_fare/simulation_screen_container"; + +const SimulationScreenPage = ({ opts = {} }) => { + const { id } = useParams() as { id: string }; + return ; +}; + +export default SimulationScreenPage; diff --git a/lib/screens/v2/screen_data.ex b/lib/screens/v2/screen_data.ex index 0d82a1c89..aa30a3612 100644 --- a/lib/screens/v2/screen_data.ex +++ b/lib/screens/v2/screen_data.ex @@ -58,7 +58,7 @@ defmodule Screens.V2.ScreenData do screen_data = fetch_data(config) full_page_data = screen_data |> resolve_paging(refresh_rate) |> serialize() - paged_slot_data = screen_data |> get_paged_slots() |> serialize_paged_slots() + paged_slot_data = screen_data |> get_paged_slots() |> serialize_paged_slots(config.app_id) response(data: %{full_page: full_page_data, flex_zone: paged_slot_data}) end @@ -401,7 +401,7 @@ defmodule Screens.V2.ScreenData do Template.position_widget_instances(layout, serialized_instance_map, paging_metadata) end - defp serialize_paged_slots({instance_map, layout}) do + defp serialize_paged_slots({instance_map, layout}, app_id) do # instance_map looks like: # %{{page_index, slot_id} => instance} @@ -410,7 +410,7 @@ defmodule Screens.V2.ScreenData do instance_map |> Enum.group_by( - fn {paged_slot_id, _} -> Template.get_page(paged_slot_id) end, + &paged_slot_key(&1, app_id), fn {paged_slot_id, instance} -> {Template.unpage(paged_slot_id), instance} end ) # %{page_index => [{slot_id, instance}]} @@ -488,4 +488,7 @@ defmodule Screens.V2.ScreenData do :ok = ScreensByAlert.put_data(screen_id, alert_ids) end + + defp paged_slot_key({paged_slot_id, _}, :pre_fare_v2), do: Template.get_slot_id(paged_slot_id) + defp paged_slot_key({paged_slot_id, _}, _), do: Template.get_page(paged_slot_id) end