diff --git a/assets/src/app.tsx b/assets/src/app.tsx index 62cd21653..a4cc4d515 100644 --- a/assets/src/app.tsx +++ b/assets/src/app.tsx @@ -20,6 +20,7 @@ import AppStateWrapper from "./components/appStateWrapper" import { tagManagerIdentify } from "./helpers/googleTagManager" import { fullStoryInit } from "./helpers/fullStory" import inTestGroup, { TestGroups } from "./userInTestGroup" +import { userUuid } from "./util/userUuid" document.documentElement.dataset.demoMode = inTestGroup( TestGroups.DemoMode @@ -37,11 +38,7 @@ sentryInit( window.sentryInitialization?.orgSlug ) -const userUuid = document - .querySelector("meta[name=user-uuid]") - ?.getAttribute("content") - -tagManagerIdentify(userUuid) +tagManagerIdentify(userUuid()) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const root = createRoot(document.getElementById("app")!) diff --git a/assets/src/components/detours/detourPanels/activeDetourPanel.tsx b/assets/src/components/detours/detourPanels/activeDetourPanel.tsx index 1a475e018..58b4f7625 100644 --- a/assets/src/components/detours/detourPanels/activeDetourPanel.tsx +++ b/assets/src/components/detours/detourPanels/activeDetourPanel.tsx @@ -80,12 +80,6 @@ export const ActiveDetourPanel = ({ routeDirection={routeDirection} /> - {connectionPoints && ( - - )} - - {missedStops && } -

Detour Directions

{directions ? ( @@ -102,6 +96,12 @@ export const ActiveDetourPanel = ({ ) : null}
+ + {connectionPoints && ( + + )} + + {missedStops && } diff --git a/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx b/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx index 604d22ac1..daf544488 100644 --- a/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx +++ b/assets/src/components/detours/detourPanels/detourFinishedPanel.tsx @@ -1,4 +1,4 @@ -import React, { PropsWithChildren } from "react" +import React, { PropsWithChildren, ReactNode } from "react" import { Button, Form } from "react-bootstrap" import * as BsIcons from "../../../helpers/bsIcons" import { Panel } from "../diversionPage" @@ -17,6 +17,7 @@ interface DetourFinishedPanelProps extends PropsWithChildren { missedStops?: Stop[] onChangeDetourText: (value: string) => void onActivateDetour?: () => void + affectedRoute?: ReactNode } export const DetourFinishedPanel = ({ @@ -28,6 +29,7 @@ export const DetourFinishedPanel = ({ onChangeDetourText, onActivateDetour, children, + affectedRoute, }: DetourFinishedPanelProps) => ( @@ -46,14 +48,16 @@ export const DetourFinishedPanel = ({ Edit + {affectedRoute} +

Directions

- {/* + {/* We need a way to let the form area take up exactly the space of its content (to avoid double scrollbars). We used this approach: https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas - The result is that the Form.Control has an invisible twin that helps the - wrapper grow to the appropriate size, and then the Form.Control likewise + The result is that the Form.Control has an invisible twin that helps the + wrapper grow to the appropriate size, and then the Form.Control likewise assumes that space. All styles that affect layout must be identical (e.g., `border`, `padding`, `margin`, `font`) between the `` and the `.c-autosized-textarea::after` pseudo-element. diff --git a/assets/src/components/detours/detourPanels/pastDetourPanel.tsx b/assets/src/components/detours/detourPanels/pastDetourPanel.tsx index 6765d33f4..f2f50560d 100644 --- a/assets/src/components/detours/detourPanels/pastDetourPanel.tsx +++ b/assets/src/components/detours/detourPanels/pastDetourPanel.tsx @@ -65,12 +65,6 @@ export const PastDetourPanel = ({ routeDirection={routeDirection} /> - {connectionPoints && ( - - )} - - {missedStops && } -

Detour Directions

{directions ? ( @@ -87,6 +81,12 @@ export const PastDetourPanel = ({ ) : null}
+ + {connectionPoints && ( + + )} + + {missedStops && }
diff --git a/assets/src/components/detours/diversionPage.tsx b/assets/src/components/detours/diversionPage.tsx index b23da9cee..1f0e736c7 100644 --- a/assets/src/components/detours/diversionPage.tsx +++ b/assets/src/components/detours/diversionPage.tsx @@ -30,6 +30,7 @@ import { DeactivateDetourModal } from "./deactivateDetourModal" import useScreenSize from "../../hooks/useScreenSize" import { Drawer } from "../drawer" import { isMobile } from "../../util/screenSize" +import { AffectedRoute } from "./detourPanelComponents" const displayFieldsFromRouteAndPattern = ( route: Route, @@ -143,17 +144,17 @@ export const DiversionPage = ({ `Detour ${routeName} ${routeDirection}`, routeOrigin, , + "Turn-by-Turn Directions:", + ...(editedDirections + ? [editedDirections] + : extendedDirections?.map((v) => v.instruction) ?? []), + , "Connection Points:", connectionPoints?.start?.name ?? "N/A", connectionPoints?.end?.name ?? "N/A", , `Missed Stops (${missedStops?.length}):`, ...(missedStops?.map(({ name }) => name) ?? ["no stops"]), - , - "Turn-by-Turn Directions:", - ...(editedDirections - ? [editedDirections] - : extendedDirections?.map((v) => v.instruction) ?? []), ].join("\n") const routes = useContext(RoutesContext) @@ -270,6 +271,14 @@ export const DiversionPage = ({ } : undefined } + affectedRoute={ + + } > {snapshot.matches({ "Detour Drawing": { diff --git a/assets/src/util/userUuid.ts b/assets/src/util/userUuid.ts new file mode 100644 index 000000000..fd14e07af --- /dev/null +++ b/assets/src/util/userUuid.ts @@ -0,0 +1,2 @@ +export const userUuid = (): string | null | undefined => + document.querySelector("meta[name=user-uuid]")?.getAttribute("content") diff --git a/assets/stories/skate-components/detours/detourFinishedPanel.stories.tsx b/assets/stories/skate-components/detours/detourFinishedPanel.stories.tsx index 856e43a06..cc47ee111 100644 --- a/assets/stories/skate-components/detours/detourFinishedPanel.stories.tsx +++ b/assets/stories/skate-components/detours/detourFinishedPanel.stories.tsx @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react" import { DetourFinishedPanel } from "../../../src/components/detours/detourPanels/detourFinishedPanel" import React from "react" +import { AffectedRoute } from "../../../src/components/detours/detourPanelComponents" // Copied from Figma const defaultText = [ @@ -41,6 +42,16 @@ const meta = { args: { copyableDetourText: defaultText, editableDirections: turnByTurn, + affectedRoute: ( + <> + + + ), }, // The bootstrap CSS reset is supposed to set box-sizing: border-box by // default, we should be able to remove this after that is added diff --git a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap index b630c50f1..75670605e 100644 --- a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap +++ b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap @@ -456,6 +456,43 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on Edit +
+

+ Affected route +

+
+
+ 2 +
+
+

+ Headsign 2 +

+

+ Route pattern From A2 - To B2 +

+

+ Outbound +

+
+
+

@@ -1270,6 +1307,43 @@ exports[`Detours Page: Open a Detour renders detour details modal to match mocke Edit +
+

+ Affected route +

+
+
+ 1 +
+
+

+ Headsign 1 +

+

+ Route pattern From A1 - To B1 +

+

+ Outbound +

+
+
+

diff --git a/assets/tests/components/detours/diversionPage.test.tsx b/assets/tests/components/detours/diversionPage.test.tsx index 13be7cc9f..83f466486 100644 --- a/assets/tests/components/detours/diversionPage.test.tsx +++ b/assets/tests/components/detours/diversionPage.test.tsx @@ -1291,19 +1291,19 @@ describe("DiversionPage", () => { `Detour ${routeName} ${routeDirection}`, routeOrigin, , - "Connection Points:", - start.name, - end.name, - , - `Missed Stops (${stops.length}):`, - ...stops.map(({ name }) => name), - , "Turn-by-Turn Directions:", "From Avenue 1 & Street 2", "Turn left on Main Street", "Turn right on High Street", "Turn sharp right on Broadway", "Regular Route", + , + "Connection Points:", + start.name, + end.name, + , + `Missed Stops (${stops.length}):`, + ...stops.map(({ name }) => name), ].join("\n") ) ) diff --git a/lib/skate/detours/detours.ex b/lib/skate/detours/detours.ex index d13c1dec3..f484e6ea9 100644 --- a/lib/skate/detours/detours.ex +++ b/lib/skate/detours/detours.ex @@ -64,18 +64,19 @@ defmodule Skate.Detours.Detours do def grouped_detours(user_id) do detours = list_detours() - |> Enum.map(fn detour -> db_detour_to_detour(detour, user_id) end) + |> Enum.map(&db_detour_to_detour/1) |> Enum.filter(& &1) |> Enum.group_by(fn detour -> detour.status end) %{ active: Map.get(detours, :active), - draft: Map.get(detours, :draft), + draft: + detours |> Map.get(:draft) |> Enum.filter(fn detour -> detour.author_id == user_id end), past: Map.get(detours, :past) } end - @spec db_detour_to_detour(Detour.t(), integer() | nil) :: DetailedDetour.t() | nil + @spec db_detour_to_detour(Detour.t()) :: DetailedDetour.t() | nil def db_detour_to_detour( %{ state: %{ @@ -85,8 +86,7 @@ defmodule Skate.Detours.Detours do "nearestIntersection" => nearest_intersection } } - } = db_detour, - user_id + } = db_detour ) do direction = Map.get(direction_names, Integer.to_string(direction_id)) @@ -98,11 +98,11 @@ defmodule Skate.Detours.Detours do intersection: nearest_intersection, updated_at: timestamp_to_unix(db_detour.updated_at), author_id: db_detour.author_id, - status: categorize_detour(db_detour, user_id) + status: categorize_detour(db_detour) } end - def db_detour_to_detour(invalid_detour, _) do + def db_detour_to_detour(invalid_detour) do Sentry.capture_message("Detour error: the detour has an outdated schema", extra: %{error: invalid_detour} ) @@ -119,22 +119,16 @@ defmodule Skate.Detours.Detours do otherwise returns `nil` if it is a draft but does not belong to the provided user """ - @spec categorize_detour(detour :: map(), user_id :: Skate.Settings.Db.User.id()) :: - detour_type() | nil - def categorize_detour( - %{state: %{"value" => %{"Detour Drawing" => %{"Active" => _}}}}, - _user_id - ), - do: :active - - def categorize_detour(%{state: %{"value" => %{"Detour Drawing" => "Past"}}}, _user_id), + @spec categorize_detour(detour :: map()) :: detour_type() + def categorize_detour(%{state: %{"value" => %{"Detour Drawing" => %{"Active" => _}}}}), + do: :active + + def categorize_detour(%{state: %{"value" => %{"Detour Drawing" => "Past"}}}), do: :past - def categorize_detour(_detour_context, nil = _user_id), do: :draft - def categorize_detour(%{author_id: author_id}, user_id) when author_id == user_id, do: :draft - def categorize_detour(_, _), do: nil - - @spec get_detour_route(detour :: map()) :: String.t() + def categorize_detour(_detour_context), do: :draft + + @spec get_detour_route(detour :: map()) :: String.t() defp get_detour_route(%{state: %{"context" => %{"route" => %{"name" => route_name}}}}), do: route_name @@ -314,23 +308,19 @@ defmodule Skate.Detours.Detours do Retrieves a `Skate.Detours.Db.Detour` from the database by it's ID and then resolves the detour's category via `categorize_detour/2` """ - @spec categorize_detour_by_id( - detour_id :: nil | integer(), - user_id :: Skate.Settings.Db.User.id() - ) :: detour_type() | nil - def categorize_detour_by_id(nil = _detour_id, _user_id), do: nil + @spec categorize_detour_by_id(detour_id :: nil | integer()) :: detour_type() | nil + def categorize_detour_by_id(nil = _detour_id), do: nil - def categorize_detour_by_id(detour_id, user_id) do + def categorize_detour_by_id(detour_id) do case Skate.Repo.get(Detour, detour_id) do - %Detour{} = detour -> categorize_detour(detour, user_id) + %Detour{} = detour -> categorize_detour(detour) _ -> nil end end @spec send_notification( new_record :: Skate.Detours.Db.Detour.t() | nil, - previous_record :: Skate.Detours.Db.Detour.t() | nil, - user_id :: Skate.Settings.Db.User.id() | nil + previous_record :: Skate.Detours.Db.Detour.t() | nil ) :: :ok | nil @spec send_notification(%{ next_detour: Skate.Detours.Db.Detour.t() | nil, @@ -339,17 +329,16 @@ defmodule Skate.Detours.Detours do }) :: :ok | nil defp send_notification( %Detour{} = new_record, - %Detour{} = previous_record, - user_id + %Detour{} = previous_record ) do send_notification(%{ next_detour: new_record, - previous: categorize_detour(previous_record, user_id), - next: categorize_detour(new_record, user_id) + previous: categorize_detour(previous_record), + next: categorize_detour(new_record) }) end - defp send_notification(_, _, _), do: nil + defp send_notification(_, _), do: nil defp send_notification(%{ next: :active, diff --git a/lib/skate_web/controllers/detours_admin_controller.ex b/lib/skate_web/controllers/detours_admin_controller.ex index 67ea940f1..29c3bc9dd 100644 --- a/lib/skate_web/controllers/detours_admin_controller.ex +++ b/lib/skate_web/controllers/detours_admin_controller.ex @@ -13,7 +13,7 @@ defmodule SkateWeb.DetoursAdminController do detours = Enum.map(raw_detours, fn detour -> - case Detours.db_detour_to_detour(detour, nil) do + case Detours.db_detour_to_detour(detour) do nil -> nil