From be20fe7a8fb4b9dd84bd8b89736a8cfc1d4b0c8e Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Mon, 6 Jan 2025 10:21:44 -0600 Subject: [PATCH 1/7] first pass at swapping in new trip planner --- .../scenarios/plan-a-trip-from-homepage.js | 2 +- integration/scenarios/plan-a-trip.js | 24 +- .../controllers/places_controller.ex | 20 +- .../controllers/trip_plan_controller.ex | 606 +++---- lib/dotcom_web/controllers/vote_controller.ex | 130 +- lib/dotcom_web/live/trip_planner.ex | 2 +- lib/dotcom_web/router.ex | 13 +- .../templates/fare/_nearby_locations.html.eex | 2 +- .../templates/layout/live.html.heex | 3 + lib/dotcom_web/templates/vote/show.html.heex | 4 +- lib/dotcom_web/views/vote_view.ex | 3 +- .../controllers/trip_plan_controller_test.exs | 1436 ++++++++--------- 12 files changed, 1125 insertions(+), 1120 deletions(-) create mode 100644 lib/dotcom_web/templates/layout/live.html.heex diff --git a/integration/scenarios/plan-a-trip-from-homepage.js b/integration/scenarios/plan-a-trip-from-homepage.js index b4a241e98f..92bb0c83e7 100644 --- a/integration/scenarios/plan-a-trip-from-homepage.js +++ b/integration/scenarios/plan-a-trip-from-homepage.js @@ -29,7 +29,7 @@ exports.scenario = async ({ page, baseURL }) => { await expect .poll(async () => - page.locator("div.m-trip-plan-results__itinerary").count(), + page.locator("section#trip-planner-results").count(), ) .toBeGreaterThan(0); }; diff --git a/integration/scenarios/plan-a-trip.js b/integration/scenarios/plan-a-trip.js index 4473a476b1..fde2eb62be 100644 --- a/integration/scenarios/plan-a-trip.js +++ b/integration/scenarios/plan-a-trip.js @@ -3,29 +3,35 @@ const { expect } = require("@playwright/test"); exports.scenario = async ({ page, baseURL }) => { await page.goto(`${baseURL}/trip-planner`); - await page.locator("input#from").pressSequentially("North Station"); + await expect( + page.getByRole("heading", { name: "Trip Planner" }), + ).toBeVisible(); + + await page.locator("fieldset#trip-planner-locations-from input[type='search']").pressSequentially("North Station"); await page.waitForSelector( - "div#from-autocomplete-results span.c-search-bar__-dropdown-menu", + "ul.aa-List", ); await page.keyboard.press("ArrowDown"); await page.keyboard.press("Enter"); - await page.locator("input#to").pressSequentially("South Station"); + // The A location pin. + await page.waitForSelector("#mbta-metro-pin-0"); + + await page.locator("fieldset#trip-planner-locations-to input[type='search']").pressSequentially("South Station"); await page.waitForSelector( - "div#to-autocomplete-results span.c-search-bar__-dropdown-menu", + "ul.aa-List", ); await page.keyboard.press("ArrowDown"); await page.keyboard.press("Enter"); - await page.locator("button#trip-plan__submit").click(); + // The B location pin. + await page.waitForSelector("#mbta-metro-pin-1"); - await expect( - page.getByRole("heading", { name: "Trip Planner" }), - ).toBeVisible(); + await page.getByText("Get trip suggestions").click(); await expect .poll(async () => - page.locator("div.m-trip-plan-results__itinerary").count(), + page.locator("section#trip-planner-results").count(), ) .toBeGreaterThan(0); }; diff --git a/lib/dotcom_web/controllers/places_controller.ex b/lib/dotcom_web/controllers/places_controller.ex index e997284c7c..931e0b2346 100644 --- a/lib/dotcom_web/controllers/places_controller.ex +++ b/lib/dotcom_web/controllers/places_controller.ex @@ -155,16 +155,16 @@ defmodule DotcomWeb.PlacesController do Map.take(map, [:latitude, :longitude]) end - vote_params = - case map do - %{formatted: formatted} -> - map - |> Map.take([:latitude, :longitude]) - |> Map.put(:address, formatted) + # vote_params = + # case map do + # %{formatted: formatted} -> + # map + # |> Map.take([:latitude, :longitude]) + # |> Map.put(:address, formatted) - _ -> - %{} - end + # _ -> + # %{} + # end map |> Map.put_new(:urls, %{ @@ -177,7 +177,7 @@ defmodule DotcomWeb.PlacesController do params ), "transit-near-me" => transit_near_me_path(DotcomWeb.Endpoint, :index, params), - "vote" => vote_path(DotcomWeb.Endpoint, :show, vote_params) + # "vote" => vote_path(DotcomWeb.Endpoint, :show, vote_params) }) end diff --git a/lib/dotcom_web/controllers/trip_plan_controller.ex b/lib/dotcom_web/controllers/trip_plan_controller.ex index cc60b210af..1fac9a0593 100644 --- a/lib/dotcom_web/controllers/trip_plan_controller.ex +++ b/lib/dotcom_web/controllers/trip_plan_controller.ex @@ -3,307 +3,307 @@ defmodule DotcomWeb.TripPlanController do Controller for trip plans. """ - use DotcomWeb, :controller - - require Logger - - alias Dotcom.TripPlan.{ - Itinerary, - ItineraryRowList, - Leg, - NamedPosition, - PersonalDetail, - Query, - RelatedLink, - TransitDetail - } - - alias Dotcom.TripPlan.Map, as: TripPlanMap - alias Routes.Route - - @location_service Application.compile_env!(:dotcom, :location_service) - - @type route_map :: %{optional(Route.id_t()) => Route.t()} - @type route_mapper :: (Route.id_t() -> Route.t() | nil) - - plug(:assign_initial_map) - plug(:breadcrumbs) - plug(:modes) - plug(:wheelchair) - plug(:meta_description) - plug(:assign_params) - - def index(conn, %{"plan" => %{"to" => _to, "from" => _fr} = plan}) do - conn - |> assign(:expanded, conn.query_params["expanded"]) - |> render_plan(plan) - end - - def index(conn, _params) do - render(conn, :index) - end - - def from(conn, %{"plan" => _plan} = params) do - redirect(conn, to: trip_plan_path(conn, :index, Map.delete(params, "address"))) - end - - def from(conn, %{ - "address" => address - }) do - if String.match?(address, ~r/^(\-?\d+(\.\d+)?),(\-?\d+(\.\d+)?),.*$/) do - [latitude, longitude, name] = String.split(address, ",", parts: 3) - # Avoid extra geocode call, just use these coordinates - destination = %NamedPosition{ - latitude: String.to_float(latitude), - longitude: String.to_float(longitude), - name: name, - stop: nil - } - - do_from(conn, destination) - else - updated_address = check_address(address) - - case @location_service.geocode(updated_address) do - {:ok, [geocoded_from | _]} -> - do_from(conn, NamedPosition.new(geocoded_from)) - - _ -> - # redirect to the initial index page - redirect(conn, to: trip_plan_path(conn, :index)) - end - end - end - - defp do_from(conn, destination) do - # build a default query with a pre-filled 'from' field: - query = %Query{ - from: destination, - to: {:error, :unknown}, - time: {:error, :unknown} - } - - now = Util.now() - - # build map information for a single leg with the 'from' field: - map_data = - TripPlanMap.itinerary_map([ - %Leg{ - from: destination, - to: nil, - mode: %PersonalDetail{}, - start: now, - stop: now - } - ]) - - %{markers: [marker]} = map_data - from_marker = %{marker | id: "B"} - map_info_for_from_destination = %{map_data | markers: [from_marker]} - - conn - |> assign(:query, query) - |> assign(:map_data, map_info_for_from_destination) - |> render(:index) - end - - def to(conn, %{"plan" => _plan} = params) do - redirect(conn, to: trip_plan_path(conn, :index, Map.delete(params, "address"))) - end - - def to(conn, %{ - "address" => address - }) do - if String.match?(address, ~r/^(\-?\d+(\.\d+)?),(\-?\d+(\.\d+)?),.*$/) do - [latitude, longitude, name] = String.split(address, ",", parts: 3) - # Avoid extra geocode call, just use these coordinates - destination = %NamedPosition{ - latitude: String.to_float(latitude), - longitude: String.to_float(longitude), - name: name, - stop: nil - } - - do_to(conn, destination) - else - updated_address = check_address(address) - - case @location_service.geocode(updated_address) do - {:ok, [geocoded_to | _]} -> - do_to(conn, NamedPosition.new(geocoded_to)) - - _ -> - # redirect to the initial index page - redirect(conn, to: trip_plan_path(conn, :index)) - end - end - end - - defp do_to(conn, destination) do - # build a default query with a pre-filled 'to' field: - query = %Query{ - to: destination, - time: {:error, :unknown}, - from: {:error, :unknown} - } - - now = Util.now() - - # build map information for a single leg with the 'to' field: - map_data = - TripPlanMap.itinerary_map([ - %Leg{ - from: nil, - to: destination, - mode: %PersonalDetail{}, - start: now, - stop: now - } - ]) - - %{markers: [marker]} = map_data - to_marker = %{marker | id: "B"} - map_info_for_to_destination = %{map_data | markers: [to_marker]} - - conn - |> assign(:query, query) - |> assign(:map_data, map_info_for_to_destination) - |> render(:index) - end - - defp assign_params(conn, _) do - conn - |> assign(:chosen_date_time, conn.params["plan"]["date_time"]) - |> assign(:chosen_time, conn.params["plan"]["time"]) - end - - @spec check_address(String.t()) :: String.t() - defp check_address(address) do - # address can be a String containing "lat,lon" so we check for that case - - [lat, lon] = - case String.split(address, ",", parts: 2) do - [lat, lon] -> [lat, lon] - _ -> ["error", "error"] - end - - if Float.parse(lat) == :error || Float.parse(lon) == :error do - address - else - {parsed_lat, _} = Float.parse(lat) - {parsed_lon, _} = Float.parse(lon) - - case @location_service.reverse_geocode(parsed_lat, parsed_lon) do - {:ok, [first | _]} -> - first.formatted - - _ -> - "#{lat}, #{lon}" - end - end - end - - defp get_route(link) do - if is_bitstring(link.text) do - link.text - else - link.text |> List.to_string() - end - end - - defp filter_duplicate_links(related_links) do - Enum.map(related_links, fn x -> Enum.uniq_by(x, fn y -> get_route(y) end) end) - end - - @spec render_plan(Plug.Conn.t(), map) :: Plug.Conn.t() - defp render_plan(conn, plan_params) do - query = - Query.from_query( - plan_params, - now: conn.assigns.date_time, - end_of_rating: Map.get(conn.assigns, :end_of_rating, Schedules.Repo.end_of_rating()) - ) - - itineraries = - query - |> Query.get_itineraries() - - itinerary_row_lists = itinerary_row_lists(itineraries, plan_params) - - conn - |> render( - query: query, - itineraries: itineraries, - plan_error: MapSet.to_list(query.errors), - routes: Enum.map(itineraries, &routes_for_itinerary(&1)), - itinerary_maps: Enum.map(itineraries, &TripPlanMap.itinerary_map(&1)), - related_links: - filter_duplicate_links(Enum.map(itineraries, &RelatedLink.links_for_itinerary(&1))), - itinerary_row_lists: itinerary_row_lists - ) - end - - @spec itinerary_row_lists([Itinerary.t()], map) :: [ItineraryRowList.t()] - defp itinerary_row_lists(itineraries, plan) do - Enum.map(itineraries, &ItineraryRowList.from_itinerary(&1, to_and_from(plan))) - end - - @spec assign_initial_map(Plug.Conn.t(), any()) :: Plug.Conn.t() - def assign_initial_map(conn, _opts) do - conn - |> assign(:map_data, TripPlanMap.initial_map_data()) - end - - @spec modes(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - def modes(%Plug.Conn{params: %{"plan" => %{"modes" => modes}}} = conn, _) do - assign( - conn, - :modes, - Map.new(modes, fn {mode, active?} -> {String.to_existing_atom(mode), active? === "true"} end) - ) - end - - def modes(%Plug.Conn{} = conn, _) do - assign( - conn, - :modes, - %{subway: true, bus: true, commuter_rail: true, ferry: true} - ) - end - - @spec breadcrumbs(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - defp breadcrumbs(conn, _) do - assign(conn, :breadcrumbs, [Breadcrumb.build("Trip Planner")]) - end - - @spec wheelchair(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - def wheelchair(%Plug.Conn{params: %{"plan" => plan_params}} = conn, _) do - assign(conn, :wheelchair, get_in(plan_params, ["wheelchair"]) === "true") - end - - # Initialize to checked state for trip plan accessibility - def wheelchair(%Plug.Conn{} = conn, _) do - assign(conn, :wheelchair, true) - end - - @spec routes_for_itinerary(Itinerary.t()) :: [Route.t()] - defp routes_for_itinerary(itinerary) do - itinerary.legs - |> Enum.filter(&match?(%TransitDetail{}, &1.mode)) - |> Enum.map(& &1.mode.route) - end - - @spec to_and_from(map) :: [to: String.t() | nil, from: String.t() | nil] - def to_and_from(plan) do - [to: Map.get(plan, "to"), from: Map.get(plan, "from")] - end - - defp meta_description(conn, _) do - conn - |> assign( - :meta_description, - "Plan a trip on public transit in the Greater Boston region with directions " <> - "and suggestions based on real-time data." - ) - end + # use DotcomWeb, :controller + + # require Logger + + # alias Dotcom.TripPlan.{ + # Itinerary, + # ItineraryRowList, + # Leg, + # NamedPosition, + # PersonalDetail, + # Query, + # RelatedLink, + # TransitDetail + # } + + # alias Dotcom.TripPlan.Map, as: TripPlanMap + # alias Routes.Route + + # @location_service Application.compile_env!(:dotcom, :location_service) + + # @type route_map :: %{optional(Route.id_t()) => Route.t()} + # @type route_mapper :: (Route.id_t() -> Route.t() | nil) + + # plug(:assign_initial_map) + # plug(:breadcrumbs) + # plug(:modes) + # plug(:wheelchair) + # plug(:meta_description) + # plug(:assign_params) + + # def index(conn, %{"plan" => %{"to" => _to, "from" => _fr} = plan}) do + # conn + # |> assign(:expanded, conn.query_params["expanded"]) + # |> render_plan(plan) + # end + + # def index(conn, _params) do + # render(conn, :index) + # end + + # def from(conn, %{"plan" => _plan} = params) do + # redirect(conn, to: trip_plan_path(conn, :index, Map.delete(params, "address"))) + # end + + # def from(conn, %{ + # "address" => address + # }) do + # if String.match?(address, ~r/^(\-?\d+(\.\d+)?),(\-?\d+(\.\d+)?),.*$/) do + # [latitude, longitude, name] = String.split(address, ",", parts: 3) + # # Avoid extra geocode call, just use these coordinates + # destination = %NamedPosition{ + # latitude: String.to_float(latitude), + # longitude: String.to_float(longitude), + # name: name, + # stop: nil + # } + + # do_from(conn, destination) + # else + # updated_address = check_address(address) + + # case @location_service.geocode(updated_address) do + # {:ok, [geocoded_from | _]} -> + # do_from(conn, NamedPosition.new(geocoded_from)) + + # _ -> + # # redirect to the initial index page + # redirect(conn, to: trip_plan_path(conn, :index)) + # end + # end + # end + + # defp do_from(conn, destination) do + # # build a default query with a pre-filled 'from' field: + # query = %Query{ + # from: destination, + # to: {:error, :unknown}, + # time: {:error, :unknown} + # } + + # now = Util.now() + + # # build map information for a single leg with the 'from' field: + # map_data = + # TripPlanMap.itinerary_map([ + # %Leg{ + # from: destination, + # to: nil, + # mode: %PersonalDetail{}, + # start: now, + # stop: now + # } + # ]) + + # %{markers: [marker]} = map_data + # from_marker = %{marker | id: "B"} + # map_info_for_from_destination = %{map_data | markers: [from_marker]} + + # conn + # |> assign(:query, query) + # |> assign(:map_data, map_info_for_from_destination) + # |> render(:index) + # end + + # def to(conn, %{"plan" => _plan} = params) do + # redirect(conn, to: trip_plan_path(conn, :index, Map.delete(params, "address"))) + # end + + # def to(conn, %{ + # "address" => address + # }) do + # if String.match?(address, ~r/^(\-?\d+(\.\d+)?),(\-?\d+(\.\d+)?),.*$/) do + # [latitude, longitude, name] = String.split(address, ",", parts: 3) + # # Avoid extra geocode call, just use these coordinates + # destination = %NamedPosition{ + # latitude: String.to_float(latitude), + # longitude: String.to_float(longitude), + # name: name, + # stop: nil + # } + + # do_to(conn, destination) + # else + # updated_address = check_address(address) + + # case @location_service.geocode(updated_address) do + # {:ok, [geocoded_to | _]} -> + # do_to(conn, NamedPosition.new(geocoded_to)) + + # _ -> + # # redirect to the initial index page + # redirect(conn, to: trip_plan_path(conn, :index)) + # end + # end + # end + + # defp do_to(conn, destination) do + # # build a default query with a pre-filled 'to' field: + # query = %Query{ + # to: destination, + # time: {:error, :unknown}, + # from: {:error, :unknown} + # } + + # now = Util.now() + + # # build map information for a single leg with the 'to' field: + # map_data = + # TripPlanMap.itinerary_map([ + # %Leg{ + # from: nil, + # to: destination, + # mode: %PersonalDetail{}, + # start: now, + # stop: now + # } + # ]) + + # %{markers: [marker]} = map_data + # to_marker = %{marker | id: "B"} + # map_info_for_to_destination = %{map_data | markers: [to_marker]} + + # conn + # |> assign(:query, query) + # |> assign(:map_data, map_info_for_to_destination) + # |> render(:index) + # end + + # defp assign_params(conn, _) do + # conn + # |> assign(:chosen_date_time, conn.params["plan"]["date_time"]) + # |> assign(:chosen_time, conn.params["plan"]["time"]) + # end + + # @spec check_address(String.t()) :: String.t() + # defp check_address(address) do + # # address can be a String containing "lat,lon" so we check for that case + + # [lat, lon] = + # case String.split(address, ",", parts: 2) do + # [lat, lon] -> [lat, lon] + # _ -> ["error", "error"] + # end + + # if Float.parse(lat) == :error || Float.parse(lon) == :error do + # address + # else + # {parsed_lat, _} = Float.parse(lat) + # {parsed_lon, _} = Float.parse(lon) + + # case @location_service.reverse_geocode(parsed_lat, parsed_lon) do + # {:ok, [first | _]} -> + # first.formatted + + # _ -> + # "#{lat}, #{lon}" + # end + # end + # end + + # defp get_route(link) do + # if is_bitstring(link.text) do + # link.text + # else + # link.text |> List.to_string() + # end + # end + + # defp filter_duplicate_links(related_links) do + # Enum.map(related_links, fn x -> Enum.uniq_by(x, fn y -> get_route(y) end) end) + # end + + # @spec render_plan(Plug.Conn.t(), map) :: Plug.Conn.t() + # defp render_plan(conn, plan_params) do + # query = + # Query.from_query( + # plan_params, + # now: conn.assigns.date_time, + # end_of_rating: Map.get(conn.assigns, :end_of_rating, Schedules.Repo.end_of_rating()) + # ) + + # itineraries = + # query + # |> Query.get_itineraries() + + # itinerary_row_lists = itinerary_row_lists(itineraries, plan_params) + + # conn + # |> render( + # query: query, + # itineraries: itineraries, + # plan_error: MapSet.to_list(query.errors), + # routes: Enum.map(itineraries, &routes_for_itinerary(&1)), + # itinerary_maps: Enum.map(itineraries, &TripPlanMap.itinerary_map(&1)), + # related_links: + # filter_duplicate_links(Enum.map(itineraries, &RelatedLink.links_for_itinerary(&1))), + # itinerary_row_lists: itinerary_row_lists + # ) + # end + + # @spec itinerary_row_lists([Itinerary.t()], map) :: [ItineraryRowList.t()] + # defp itinerary_row_lists(itineraries, plan) do + # Enum.map(itineraries, &ItineraryRowList.from_itinerary(&1, to_and_from(plan))) + # end + + # @spec assign_initial_map(Plug.Conn.t(), any()) :: Plug.Conn.t() + # def assign_initial_map(conn, _opts) do + # conn + # |> assign(:map_data, TripPlanMap.initial_map_data()) + # end + + # @spec modes(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() + # def modes(%Plug.Conn{params: %{"plan" => %{"modes" => modes}}} = conn, _) do + # assign( + # conn, + # :modes, + # Map.new(modes, fn {mode, active?} -> {String.to_existing_atom(mode), active? === "true"} end) + # ) + # end + + # def modes(%Plug.Conn{} = conn, _) do + # assign( + # conn, + # :modes, + # %{subway: true, bus: true, commuter_rail: true, ferry: true} + # ) + # end + + # @spec breadcrumbs(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() + # defp breadcrumbs(conn, _) do + # assign(conn, :breadcrumbs, [Breadcrumb.build("Trip Planner")]) + # end + + # @spec wheelchair(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() + # def wheelchair(%Plug.Conn{params: %{"plan" => plan_params}} = conn, _) do + # assign(conn, :wheelchair, get_in(plan_params, ["wheelchair"]) === "true") + # end + + # # Initialize to checked state for trip plan accessibility + # def wheelchair(%Plug.Conn{} = conn, _) do + # assign(conn, :wheelchair, true) + # end + + # @spec routes_for_itinerary(Itinerary.t()) :: [Route.t()] + # defp routes_for_itinerary(itinerary) do + # itinerary.legs + # |> Enum.filter(&match?(%TransitDetail{}, &1.mode)) + # |> Enum.map(& &1.mode.route) + # end + + # @spec to_and_from(map) :: [to: String.t() | nil, from: String.t() | nil] + # def to_and_from(plan) do + # [to: Map.get(plan, "to"), from: Map.get(plan, "from")] + # end + + # defp meta_description(conn, _) do + # conn + # |> assign( + # :meta_description, + # "Plan a trip on public transit in the Greater Boston region with directions " <> + # "and suggestions based on real-time data." + # ) + # end end diff --git a/lib/dotcom_web/controllers/vote_controller.ex b/lib/dotcom_web/controllers/vote_controller.ex index c16b493ba0..e887c9acea 100644 --- a/lib/dotcom_web/controllers/vote_controller.ex +++ b/lib/dotcom_web/controllers/vote_controller.ex @@ -3,81 +3,81 @@ defmodule DotcomWeb.VoteController do Handles rendering the vote widget """ - use DotcomWeb, :controller + # use DotcomWeb, :controller - import DotcomWeb.ViewHelpers, only: [cms_static_page_path: 2] + # import DotcomWeb.ViewHelpers, only: [cms_static_page_path: 2] - plug(:meta_description) - plug(:clear_polling_results) + # plug(:meta_description) + # plug(:clear_polling_results) - def show( - conn, - %{"address" => address, "latitude" => latitude, "longitude" => longitude} = _params - ) do - google_api_key = Application.get_env(:dotcom, :google_api_key) + # def show( + # conn, + # %{"address" => address, "latitude" => latitude, "longitude" => longitude} = _params + # ) do + # google_api_key = Application.get_env(:dotcom, :google_api_key) - response = - Req.get("https://www.googleapis.com/civicinfo/v2/voterinfo", - params: [ - key: google_api_key, - electionId: "9000", - address: address - ] - ) + # response = + # Req.get("https://www.googleapis.com/civicinfo/v2/voterinfo", + # params: [ + # key: google_api_key, + # electionId: "9000", + # address: address + # ] + # ) - conn = - case response do - {:ok, %{body: %{"pollingLocations" => [polling_location | _]}}} -> - polling_location_name = Recase.to_title(polling_location["address"]["locationName"]) + # conn = + # case response do + # {:ok, %{body: %{"pollingLocations" => [polling_location | _]}}} -> + # polling_location_name = Recase.to_title(polling_location["address"]["locationName"]) - params = %{ - "plan" => %{ - "from_latitude" => latitude, - "from_longitude" => longitude, - "from" => address, - "to_latitude" => polling_location["latitude"], - "to_longitude" => polling_location["longitude"], - "to" => polling_location_name - } - } + # params = %{ + # "plan" => %{ + # "from_latitude" => latitude, + # "from_longitude" => longitude, + # "from" => address, + # "to_latitude" => polling_location["latitude"], + # "to_longitude" => polling_location["longitude"], + # "to" => polling_location_name + # } + # } - conn - |> assign(:polling_location, polling_location) - |> assign(:polling_location_name, polling_location_name) - |> assign(:trip_plan_path, trip_plan_path(DotcomWeb.Endpoint, :index, params)) + # conn + # |> assign(:polling_location, polling_location) + # |> assign(:polling_location_name, polling_location_name) + # |> assign(:trip_plan_path, trip_plan_path(DotcomWeb.Endpoint, :index, params)) - _ -> - conn |> assign(:polling_error, true) - end + # _ -> + # conn |> assign(:polling_error, true) + # end - conn - |> assign(:should_scroll, true) - |> assign(:breadcrumbs, [ - Breadcrumb.build("Take the T to Vote", cms_static_page_path(conn, "/vote")) - ]) - |> render("show.html") - end + # conn + # |> assign(:should_scroll, true) + # |> assign(:breadcrumbs, [ + # Breadcrumb.build("Take the T to Vote", cms_static_page_path(conn, "/vote")) + # ]) + # |> render("show.html") + # end - def show(conn, _params) do - conn - |> assign(:breadcrumbs, [ - Breadcrumb.build("Vote", cms_static_page_path(conn, "/vote")) - ]) - |> render("show.html") - end + # def show(conn, _params) do + # conn + # |> assign(:breadcrumbs, [ + # Breadcrumb.build("Vote", cms_static_page_path(conn, "/vote")) + # ]) + # |> render("show.html") + # end - defp meta_description(conn, _) do - conn - |> assign( - :meta_description, - "Tuesday, November 5 is the last day to vote in the 2024 general election. Use the T to get to your polling location." - ) - end + # defp meta_description(conn, _) do + # conn + # |> assign( + # :meta_description, + # "Tuesday, November 5 is the last day to vote in the 2024 general election. Use the T to get to your polling location." + # ) + # end - defp clear_polling_results(conn, _) do - conn - |> assign(:polling_location, nil) - |> assign(:polling_error, false) - |> assign(:should_scroll, false) - end + # defp clear_polling_results(conn, _) do + # conn + # |> assign(:polling_location, nil) + # |> assign(:polling_error, false) + # |> assign(:should_scroll, false) + # end end diff --git a/lib/dotcom_web/live/trip_planner.ex b/lib/dotcom_web/live/trip_planner.ex index 1b7c2bc651..7029b32a96 100644 --- a/lib/dotcom_web/live/trip_planner.ex +++ b/lib/dotcom_web/live/trip_planner.ex @@ -62,7 +62,7 @@ defmodule DotcomWeb.Live.TripPlanner do """ def render(assigns) do ~H""" -

Trip Planner Preview

+

Trip Planner

<.input_form class="mb-4" changeset={@input_form.changeset} />
diff --git a/lib/dotcom_web/router.ex b/lib/dotcom_web/router.ex index e993fcf159..a2dcd73a7f 100644 --- a/lib/dotcom_web/router.ex +++ b/lib/dotcom_web/router.ex @@ -227,11 +227,6 @@ defmodule DotcomWeb.Router do get("/style-guide/:section/:subpage", StyleGuideController, :show) get("/transit-near-me", TransitNearMeController, :index) resources("/alerts", AlertController, only: [:index, :show]) - get("/trip-planner", TripPlanController, :index) - get("/trip-planner/from/", Redirector, to: "/trip-planner") - get("/trip-planner/from/:address", TripPlanController, :from) - get("/trip-planner/to/", Redirector, to: "/trip-planner") - get("/trip-planner/to/:address", TripPlanController, :to) delete("/trip-planner/feedback", TripPlan.Feedback, :delete) post("/trip-planner/feedback", TripPlan.Feedback, :put) get("/customer-support", CustomerSupportController, :index) @@ -242,7 +237,7 @@ defmodule DotcomWeb.Router do post("/search/query", SearchController, :query) post("/search/click", SearchController, :click) get("/bus-stop-changes", BusStopChangeController, :show) - get("/vote", VoteController, :show) + # get("/vote", VoteController, :show) end scope "/", DotcomWeb do @@ -263,11 +258,11 @@ defmodule DotcomWeb.Router do end end - scope "/preview", DotcomWeb do + scope "/", DotcomWeb do import Phoenix.LiveView.Router - pipe_through([:browser, :browser_live, :basic_auth_readonly]) + pipe_through([:browser, :browser_live]) - live_session :rider, layout: {DotcomWeb.LayoutView, :preview} do + live_session :rider, layout: {DotcomWeb.LayoutView, :live} do live("/trip-planner", Live.TripPlanner) end end diff --git a/lib/dotcom_web/templates/fare/_nearby_locations.html.eex b/lib/dotcom_web/templates/fare/_nearby_locations.html.eex index e09fc7fe47..750250fcaa 100644 --- a/lib/dotcom_web/templates/fare/_nearby_locations.html.eex +++ b/lib/dotcom_web/templates/fare/_nearby_locations.html.eex @@ -36,7 +36,7 @@
- + Plan your trip
@@ -56,7 +56,7 @@ Secretary of State's official site to find your polling place, and then use the - + MBTA Trip Planner to plan your trip. diff --git a/lib/dotcom_web/views/vote_view.ex b/lib/dotcom_web/views/vote_view.ex index e05f122a07..f13877a231 100644 --- a/lib/dotcom_web/views/vote_view.ex +++ b/lib/dotcom_web/views/vote_view.ex @@ -2,5 +2,6 @@ defmodule DotcomWeb.VoteView do @moduledoc """ View for the vote widget """ - use DotcomWeb, :view + + # use DotcomWeb, :view end diff --git a/test/dotcom_web/controllers/trip_plan_controller_test.exs b/test/dotcom_web/controllers/trip_plan_controller_test.exs index 0e2cb30203..547fe4b681 100644 --- a/test/dotcom_web/controllers/trip_plan_controller_test.exs +++ b/test/dotcom_web/controllers/trip_plan_controller_test.exs @@ -1,720 +1,720 @@ defmodule DotcomWeb.TripPlanControllerTest do - use DotcomWeb.ConnCase, async: true - - alias Dotcom.TripPlan.{Itinerary, PersonalDetail, Query, TransitDetail} - alias Fares.Fare - - import Test.Support.Factories.LocationService.LocationService - - doctest DotcomWeb.TripPlanController - - import Mox - - @system_time "2017-01-01T12:20:00-05:00" - @morning %{ - "year" => "2017", - "month" => "1", - "day" => "2", - "hour" => "9", - "minute" => "30", - "am_pm" => "AM" - } - @afternoon %{ - "year" => "2017", - "month" => "1", - "day" => "2", - "hour" => "5", - "minute" => "30", - "am_pm" => "PM" - } - @after_hours %{ - "year" => "2017", - "month" => "1", - "day" => "2", - "hour" => "3", - "minute" => "00", - "am_pm" => "AM" - } - @modes %{"subway" => "true", "commuter_rail" => "true", "bus" => "false", "ferry" => "false"} - - @good_params %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => @afternoon, - "time" => "depart", - "modes" => @modes, - "wheelchair" => "true" - } - } - - @bad_params %{ - "date_time" => @system_time, - "plan" => %{"from" => "no results", "to" => "too many results", "date_time" => @afternoon} - } - - setup :verify_on_exit! - - setup do - stub(MBTA.Api.Mock, :get_json, fn "/schedules/", [route: "Red", date: "1970-01-01"] -> - {:error, - [ - %JsonApi.Error{ - code: "no_service", - source: %{ - "parameter" => "date" - }, - detail: "The current rating does not describe service on that date.", - meta: %{ - "end_date" => "2024-06-15", - "start_date" => "2024-05-10", - "version" => "Spring 2024, 2024-05-17T21:10:15+00:00, version D" - } - } - ]} - end) - - stub(OpenTripPlannerClient.Mock, :plan, fn _from, _to, _opts -> - {:ok, %OpenTripPlannerClient.Plan{itineraries: []}} - end) - - stub(LocationService.Mock, :geocode, fn name -> - {:ok, build_list(2, :address, %{formatted: name})} - end) - - stub(Stops.Repo.Mock, :get_parent, fn _ -> - %Stops.Stop{} - end) - - cache = Application.get_env(:dotcom, :cache) - cache.flush() - - conn = default_conn() - - end_of_rating = - @system_time - |> Timex.parse!("{ISO:Extended}") - |> Timex.shift(months: 3) - |> DateTime.to_date() - - {:ok, conn: assign(conn, :end_of_rating, end_of_rating)} - end - - describe "index without params" do - test "renders index.html", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index)) - assert html_response(conn, 200) =~ "Trip Planner" - end - - test "assigns initial map data", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index)) - assert conn.assigns.map_data - end - - test "sets a custom meta description", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index)) - assert conn.assigns.meta_description - end - end - - describe "index with params" do - test "renders the query plan", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - response = html_response(conn, 200) - assert response =~ "Trip Planner" - assert %Query{} = conn.assigns.query - assert conn.assigns.itineraries - assert conn.assigns.routes - assert conn.assigns.itinerary_maps - assert conn.assigns.related_links - end - - test "uses current location to render a query plan", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "Your current location", - "from_latitude" => "42.3428", - "from_longitude" => "-71.0857", - "to" => "to address", - "to_latitude" => "", - "to_longitude" => "", - "date_time" => @morning, - "modes" => @modes - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - - assert html_response(conn, 200) =~ "Trip Planner" - assert %Query{} = conn.assigns.query - end - - test "sets hidden inputs for lat/lng", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "from_latitude" => "1", - "from_longitude" => "2", - "to" => "to address", - "to_latitude" => "3", - "to_longitude" => "4", - "date_time" => @morning, - "modes" => @modes - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - - resp = html_response(conn, 200) - assert from_latitude = Floki.find(resp, "#from_latitude") - assert from_longitude = Floki.find(resp, "#from_longitude") - assert to_latitude = Floki.find(resp, "#to_latitude") - assert to_longitude = Floki.find(resp, "#to_longitude") - assert List.first(Floki.attribute(from_latitude, "value")) == "1.0" - assert List.first(Floki.attribute(from_longitude, "value")) == "2.0" - assert List.first(Floki.attribute(to_latitude, "value")) == "3.0" - assert List.first(Floki.attribute(to_longitude, "value")) == "4.0" - end - - test "assigns.mode is a map of parsed mode state", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "Your current location", - "from_latitude" => "42.3428", - "from_longitude" => "-71.0857", - "to" => "to address", - "to_latitude" => "", - "to_longitude" => "", - "date_time" => @morning, - "modes" => @modes - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - - assert html_response(conn, 200) =~ "Trip Planner" - assert conn.assigns.modes == %{subway: true, commuter_rail: true, bus: false, ferry: false} - assert %Query{} = conn.assigns.query - end - - test "assigns.wheelchair uses value provided in params", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "Your current location", - "from_latitude" => "42.3428", - "from_longitude" => "-71.0857", - "to" => "to address", - "to_latitude" => "", - "to_longitude" => "", - "date_time" => @morning, - "modes" => @modes, - "wheelchair" => "true" - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - - assert html_response(conn, 200) =~ "Trip Planner" - assert conn.assigns.wheelchair == true - end - - test "can use the old date time format", %{conn: conn} do - old_dt_format = Map.delete(@afternoon, "am_pm") - - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from_address", - "from_latitude" => "", - "from_longitude" => "", - "to" => "to address", - "to_latitude" => "", - "to_longitude" => "", - "date_time" => old_dt_format, - "mode" => @modes - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert html_response(conn, 200) - end - - test "each map url has a path color", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - for {map_data, static_map} <- conn.assigns.itinerary_maps do - assert static_map =~ "color" - - for path <- map_data.polylines do - assert path.color - end - end - end - - test "renders a geocoding error", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @bad_params)) - response = html_response(conn, 200) - assert response =~ "Trip Planner" - # shows error styling on location input with "required" label - assert response =~ "(Required)" - assert %Query{} = conn.assigns.query - end - - test "assigns maps for each itinerary", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - assert conn.assigns.itinerary_maps - end - - test "gets routes from each itinerary", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - assert conn.assigns.routes - - for routes_for_itinerary <- conn.assigns.routes do - assert length(routes_for_itinerary) > 0 - end - end - - test "assigns an ItineraryRowList for each itinerary", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - assert conn.assigns.itinerary_row_lists - end - - test "adds fare data to each transit leg of each itinerary", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - assert Enum.all?(conn.assigns.itineraries, fn itinerary -> - Enum.all?(itinerary.legs, fn leg -> - match?(%PersonalDetail{}, leg.mode) || - match?( - %TransitDetail{ - fares: %{ - highest_one_way_fare: %Fares.Fare{}, - lowest_one_way_fare: %Fares.Fare{}, - reduced_one_way_fare: %Fares.Fare{} - } - }, - leg.mode - ) - end) - end) - end - - test "returns all nil fares when there is not enough information", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - for itinerary <- conn.assigns.itineraries do - for leg <- itinerary.legs do - if Dotcom.TripPlan.Leg.transit?(leg) do - assert leg.mode.fares == %{ - highest_one_way_fare: nil, - lowest_one_way_fare: nil, - reduced_one_way_fare: nil - } - end - end - end - end - - test "adds monthly pass data to each itinerary", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - assert Enum.all?(conn.assigns.itineraries, fn itinerary -> - %Itinerary{passes: %{base_month_pass: %Fare{}, recommended_month_pass: %Fare{}}} = - itinerary - end) - end - - test "renders an error if longitude and latitude from both addresses are the same", %{ - conn: conn - } do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from_latitude" => "90", - "to_latitude" => "90", - "from_longitude" => "50", - "to_longitude" => "50", - "date_time" => @afternoon, - "from" => "from St", - "to" => "from Street" - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert conn.assigns.plan_error == [:same_address] - assert html_response(conn, 200) - assert html_response(conn, 200) =~ "two different locations" - end - - test "doesn't render an error if longitudes and latitudes are unique", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from_latitude" => "90", - "to_latitude" => "90.5", - "from_longitude" => "50.5", - "to_longitude" => "50", - "date_time" => @afternoon, - "from" => "from St", - "to" => "from Street" - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert conn.assigns.plan_error == [] - assert html_response(conn, 200) - end - - test "renders an error if to and from address are the same", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from", - "to" => "from", - "date_time" => @afternoon - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert conn.assigns.plan_error == [:same_address] - assert html_response(conn, 200) - assert html_response(conn, 200) =~ "two different locations" - end - - test "doesn't render an error if to and from address are unique", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from", - "to" => "to", - "date_time" => @afternoon - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert conn.assigns.plan_error == [] - assert html_response(conn, 200) - end - - test "handles empty lat/lng", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from", - "to" => "from", - "to_latitude" => "", - "to_longitude" => "", - "from_latitude" => "", - "from_longitude" => "", - "date_time" => @afternoon - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert conn.assigns.plan_error == [:same_address] - assert html_response(conn, 200) - assert html_response(conn, 200) =~ "two different locations" - end - - test "bad date input: fictional day", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => %{@morning | "month" => "6", "day" => "31"} - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - response = html_response(conn, 200) - assert response =~ "Date is not valid" - end - - test "bad date input: partial input", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => %{@morning | "month" => ""} - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - response = html_response(conn, 200) - assert response =~ "Date is not valid" - end - - test "bad date input: corrupt day", %{conn: conn} do - date_input = %{ - "year" => "A", - "month" => "B", - "day" => "C", - "hour" => "D", - "minute" => "E", - "am_pm" => "PM" - } - - params = %{ - "date_time" => @system_time, - "plan" => %{"from" => "from address", "to" => "to address", "date_time" => date_input} - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - response = html_response(conn, 200) - assert response =~ "Date is not valid" - end - - test "bad date input: too far in future", %{conn: conn} do - end_date = Timex.shift(Schedules.Repo.end_of_rating(), days: 1) - - end_date_as_params = %{ - "month" => Integer.to_string(end_date.month), - "day" => Integer.to_string(end_date.day), - "year" => Integer.to_string(end_date.year), - "hour" => "12", - "minute" => "15", - "am_pm" => "PM" - } - - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => end_date_as_params, - "time" => "depart" - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - response = html_response(conn, 200) - assert Map.get(conn.assigns, :plan_error) == [:too_future] - assert response =~ "Date is too far in the future" - - expected = - [:too_future] - |> DotcomWeb.TripPlanView.plan_error_description() - |> IO.iodata_to_binary() - - assert response =~ expected - end - - test "bad date input: date in past", %{conn: conn} do - past_date = - @system_time - |> Timex.parse!("{ISO:Extended}") - |> Timex.shift(days: -10) - - past_date_as_params = %{ - "month" => Integer.to_string(past_date.month), - "day" => Integer.to_string(past_date.day), - "year" => Integer.to_string(past_date.year), - "hour" => "12", - "minute" => "15", - "am_pm" => "PM" - } - - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => past_date_as_params, - "time" => "depart" - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - response = html_response(conn, 200) - assert Map.get(conn.assigns, :plan_error) == [:past] - assert response =~ "Date is in the past" - end - - test "handles missing date and time params, using today's values if they are missing", - %{conn: conn} do - wrong_datetime_params = %{ - "year" => "2017", - "day" => "2", - "hour" => "9", - "am_pm" => "AM" - } - - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => wrong_datetime_params - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert html_response(conn, 200) - end - - test "handles non-existing date and time params, using today's values", - %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => %{} - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert html_response(conn, 200) - end - - test "does not need to default date and time params as they are present", - %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => @morning - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - assert html_response(conn, 200) - end - - test "good date input: date within service date of end of rating", %{conn: conn} do - # after midnight but before end of service on last day of rating - # should still be inside of the rating - - date = Timex.shift(conn.assigns.end_of_rating, days: 1) - - date_params = %{ - "month" => Integer.to_string(date.month), - "day" => Integer.to_string(date.day), - "year" => Integer.to_string(date.year), - "hour" => "12", - "minute" => "15", - "am_pm" => "AM" - } - - params = %{ - "date_time" => @system_time, - "plan" => %{"from" => "from address", "to" => "to address", "date_time" => date_params} - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - - response = html_response(conn, 200) - assert Map.get(conn.assigns, :plan_error) == [] - refute response =~ "Date is too far in the future" - refute response =~ "Date is not valid" - end - - test "hour and minute are processed correctly when provided as single digits", %{conn: conn} do - params = %{ - "date_time" => @system_time, - "plan" => %{ - "from" => "from address", - "to" => "to address", - "date_time" => %{@after_hours | "hour" => "1", "minute" => "1"}, - "time" => "depart" - } - } - - conn = get(conn, trip_plan_path(conn, :index, params)) - response = html_response(conn, 200) - assert Map.get(conn.assigns, :plan_error) == [] - refute response =~ "Date is not valid" - end - end - - describe "/from/ address path" do - test "gets a valid address in the 'from' field", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :from, "Boston Common")) - - assert conn.assigns.query.from.name == "Boston Common" - end - - test "uses expected values when addres is formatted latitutde,longitude,stopName", %{ - conn: conn - } do - conn = get(conn, trip_plan_path(conn, :from, "42.395428,-71.142483,Cobbs Corner, Canton")) - - assert html_response(conn, 200) - assert conn.assigns.query.from.name == "Cobbs Corner, Canton" - assert conn.assigns.query.from.latitude == 42.395428 - assert conn.assigns.query.from.longitude == -71.142483 - end - - test "is unable to get address so it redirects to index", %{conn: conn} do - expect(LocationService.Mock, :geocode, fn _ -> - {:error, :something} - end) - - conn = get(conn, trip_plan_path(conn, :from, "Atlantis")) - assert html_response(conn, 302) =~ "/trip-planner" - end - - test "when 'plan' is part of the parameters, it redirects to the usual trip planner", %{ - conn: conn - } do - plan_params = %{"plan" => %{"from" => "from address", "to" => "to address"}} - - conn = - get( - conn, - trip_plan_path(conn, :from, "Address", plan_params) - ) - - assert redirected_to(conn) == trip_plan_path(conn, :index, plan_params) - end - end - - describe "/to/ address path" do - test "gets a valid address in the 'to' field", %{conn: conn} do - conn = get(conn, trip_plan_path(conn, :to, "Boston Common")) - assert conn.assigns.query.to.name == "Boston Common" - end - - test "uses expected values when address is formatted latitutde,longitude,stopName", %{ - conn: conn - } do - conn = get(conn, trip_plan_path(conn, :to, "42.395428,-71.142483,Cobbs Corner, Canton")) - - assert html_response(conn, 200) - assert conn.assigns.query.to.name == "Cobbs Corner, Canton" - assert conn.assigns.query.to.latitude == 42.395428 - assert conn.assigns.query.to.longitude == -71.142483 - end - - test "is unable to get address so it redirects to index", %{conn: conn} do - expect(LocationService.Mock, :geocode, fn _ -> - {:error, :something} - end) - - conn = get(conn, trip_plan_path(conn, :to, "Atlantis")) - assert html_response(conn, 302) =~ "/trip-planner" - end - - test "when 'plan' is part of the parameters, it redirects to the usual trip planner", %{ - conn: conn - } do - plan_params = %{"plan" => %{"from" => "from address", "to" => "to address"}} - - conn = - get( - conn, - trip_plan_path(conn, :to, "Address", plan_params) - ) - - assert redirected_to(conn) == trip_plan_path(conn, :index, plan_params) - end - end + # use DotcomWeb.ConnCase, async: true + + # alias Dotcom.TripPlan.{Itinerary, PersonalDetail, Query, TransitDetail} + # alias Fares.Fare + + # import Test.Support.Factories.LocationService.LocationService + + # doctest DotcomWeb.TripPlanController + + # import Mox + + # @system_time "2017-01-01T12:20:00-05:00" + # @morning %{ + # "year" => "2017", + # "month" => "1", + # "day" => "2", + # "hour" => "9", + # "minute" => "30", + # "am_pm" => "AM" + # } + # @afternoon %{ + # "year" => "2017", + # "month" => "1", + # "day" => "2", + # "hour" => "5", + # "minute" => "30", + # "am_pm" => "PM" + # } + # @after_hours %{ + # "year" => "2017", + # "month" => "1", + # "day" => "2", + # "hour" => "3", + # "minute" => "00", + # "am_pm" => "AM" + # } + # @modes %{"subway" => "true", "commuter_rail" => "true", "bus" => "false", "ferry" => "false"} + + # @good_params %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => @afternoon, + # "time" => "depart", + # "modes" => @modes, + # "wheelchair" => "true" + # } + # } + + # @bad_params %{ + # "date_time" => @system_time, + # "plan" => %{"from" => "no results", "to" => "too many results", "date_time" => @afternoon} + # } + + # setup :verify_on_exit! + + # setup do + # stub(MBTA.Api.Mock, :get_json, fn "/schedules/", [route: "Red", date: "1970-01-01"] -> + # {:error, + # [ + # %JsonApi.Error{ + # code: "no_service", + # source: %{ + # "parameter" => "date" + # }, + # detail: "The current rating does not describe service on that date.", + # meta: %{ + # "end_date" => "2024-06-15", + # "start_date" => "2024-05-10", + # "version" => "Spring 2024, 2024-05-17T21:10:15+00:00, version D" + # } + # } + # ]} + # end) + + # stub(OpenTripPlannerClient.Mock, :plan, fn _from, _to, _opts -> + # {:ok, %OpenTripPlannerClient.Plan{itineraries: []}} + # end) + + # stub(LocationService.Mock, :geocode, fn name -> + # {:ok, build_list(2, :address, %{formatted: name})} + # end) + + # stub(Stops.Repo.Mock, :get_parent, fn _ -> + # %Stops.Stop{} + # end) + + # cache = Application.get_env(:dotcom, :cache) + # cache.flush() + + # conn = default_conn() + + # end_of_rating = + # @system_time + # |> Timex.parse!("{ISO:Extended}") + # |> Timex.shift(months: 3) + # |> DateTime.to_date() + + # {:ok, conn: assign(conn, :end_of_rating, end_of_rating)} + # end + + # describe "index without params" do + # test "renders index.html", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index)) + # assert html_response(conn, 200) =~ "Trip Planner" + # end + + # test "assigns initial map data", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index)) + # assert conn.assigns.map_data + # end + + # test "sets a custom meta description", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index)) + # assert conn.assigns.meta_description + # end + # end + + # describe "index with params" do + # test "renders the query plan", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + # response = html_response(conn, 200) + # assert response =~ "Trip Planner" + # assert %Query{} = conn.assigns.query + # assert conn.assigns.itineraries + # assert conn.assigns.routes + # assert conn.assigns.itinerary_maps + # assert conn.assigns.related_links + # end + + # test "uses current location to render a query plan", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "Your current location", + # "from_latitude" => "42.3428", + # "from_longitude" => "-71.0857", + # "to" => "to address", + # "to_latitude" => "", + # "to_longitude" => "", + # "date_time" => @morning, + # "modes" => @modes + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + + # assert html_response(conn, 200) =~ "Trip Planner" + # assert %Query{} = conn.assigns.query + # end + + # test "sets hidden inputs for lat/lng", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "from_latitude" => "1", + # "from_longitude" => "2", + # "to" => "to address", + # "to_latitude" => "3", + # "to_longitude" => "4", + # "date_time" => @morning, + # "modes" => @modes + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + + # resp = html_response(conn, 200) + # assert from_latitude = Floki.find(resp, "#from_latitude") + # assert from_longitude = Floki.find(resp, "#from_longitude") + # assert to_latitude = Floki.find(resp, "#to_latitude") + # assert to_longitude = Floki.find(resp, "#to_longitude") + # assert List.first(Floki.attribute(from_latitude, "value")) == "1.0" + # assert List.first(Floki.attribute(from_longitude, "value")) == "2.0" + # assert List.first(Floki.attribute(to_latitude, "value")) == "3.0" + # assert List.first(Floki.attribute(to_longitude, "value")) == "4.0" + # end + + # test "assigns.mode is a map of parsed mode state", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "Your current location", + # "from_latitude" => "42.3428", + # "from_longitude" => "-71.0857", + # "to" => "to address", + # "to_latitude" => "", + # "to_longitude" => "", + # "date_time" => @morning, + # "modes" => @modes + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + + # assert html_response(conn, 200) =~ "Trip Planner" + # assert conn.assigns.modes == %{subway: true, commuter_rail: true, bus: false, ferry: false} + # assert %Query{} = conn.assigns.query + # end + + # test "assigns.wheelchair uses value provided in params", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "Your current location", + # "from_latitude" => "42.3428", + # "from_longitude" => "-71.0857", + # "to" => "to address", + # "to_latitude" => "", + # "to_longitude" => "", + # "date_time" => @morning, + # "modes" => @modes, + # "wheelchair" => "true" + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + + # assert html_response(conn, 200) =~ "Trip Planner" + # assert conn.assigns.wheelchair == true + # end + + # test "can use the old date time format", %{conn: conn} do + # old_dt_format = Map.delete(@afternoon, "am_pm") + + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from_address", + # "from_latitude" => "", + # "from_longitude" => "", + # "to" => "to address", + # "to_latitude" => "", + # "to_longitude" => "", + # "date_time" => old_dt_format, + # "mode" => @modes + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert html_response(conn, 200) + # end + + # test "each map url has a path color", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + + # for {map_data, static_map} <- conn.assigns.itinerary_maps do + # assert static_map =~ "color" + + # for path <- map_data.polylines do + # assert path.color + # end + # end + # end + + # test "renders a geocoding error", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @bad_params)) + # response = html_response(conn, 200) + # assert response =~ "Trip Planner" + # # shows error styling on location input with "required" label + # assert response =~ "(Required)" + # assert %Query{} = conn.assigns.query + # end + + # test "assigns maps for each itinerary", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + # assert conn.assigns.itinerary_maps + # end + + # test "gets routes from each itinerary", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + # assert conn.assigns.routes + + # for routes_for_itinerary <- conn.assigns.routes do + # assert length(routes_for_itinerary) > 0 + # end + # end + + # test "assigns an ItineraryRowList for each itinerary", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + # assert conn.assigns.itinerary_row_lists + # end + + # test "adds fare data to each transit leg of each itinerary", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + + # assert Enum.all?(conn.assigns.itineraries, fn itinerary -> + # Enum.all?(itinerary.legs, fn leg -> + # match?(%PersonalDetail{}, leg.mode) || + # match?( + # %TransitDetail{ + # fares: %{ + # highest_one_way_fare: %Fares.Fare{}, + # lowest_one_way_fare: %Fares.Fare{}, + # reduced_one_way_fare: %Fares.Fare{} + # } + # }, + # leg.mode + # ) + # end) + # end) + # end + + # test "returns all nil fares when there is not enough information", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + + # for itinerary <- conn.assigns.itineraries do + # for leg <- itinerary.legs do + # if Dotcom.TripPlan.Leg.transit?(leg) do + # assert leg.mode.fares == %{ + # highest_one_way_fare: nil, + # lowest_one_way_fare: nil, + # reduced_one_way_fare: nil + # } + # end + # end + # end + # end + + # test "adds monthly pass data to each itinerary", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :index, @good_params)) + + # assert Enum.all?(conn.assigns.itineraries, fn itinerary -> + # %Itinerary{passes: %{base_month_pass: %Fare{}, recommended_month_pass: %Fare{}}} = + # itinerary + # end) + # end + + # test "renders an error if longitude and latitude from both addresses are the same", %{ + # conn: conn + # } do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from_latitude" => "90", + # "to_latitude" => "90", + # "from_longitude" => "50", + # "to_longitude" => "50", + # "date_time" => @afternoon, + # "from" => "from St", + # "to" => "from Street" + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert conn.assigns.plan_error == [:same_address] + # assert html_response(conn, 200) + # assert html_response(conn, 200) =~ "two different locations" + # end + + # test "doesn't render an error if longitudes and latitudes are unique", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from_latitude" => "90", + # "to_latitude" => "90.5", + # "from_longitude" => "50.5", + # "to_longitude" => "50", + # "date_time" => @afternoon, + # "from" => "from St", + # "to" => "from Street" + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert conn.assigns.plan_error == [] + # assert html_response(conn, 200) + # end + + # test "renders an error if to and from address are the same", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from", + # "to" => "from", + # "date_time" => @afternoon + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert conn.assigns.plan_error == [:same_address] + # assert html_response(conn, 200) + # assert html_response(conn, 200) =~ "two different locations" + # end + + # test "doesn't render an error if to and from address are unique", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from", + # "to" => "to", + # "date_time" => @afternoon + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert conn.assigns.plan_error == [] + # assert html_response(conn, 200) + # end + + # test "handles empty lat/lng", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from", + # "to" => "from", + # "to_latitude" => "", + # "to_longitude" => "", + # "from_latitude" => "", + # "from_longitude" => "", + # "date_time" => @afternoon + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert conn.assigns.plan_error == [:same_address] + # assert html_response(conn, 200) + # assert html_response(conn, 200) =~ "two different locations" + # end + + # test "bad date input: fictional day", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => %{@morning | "month" => "6", "day" => "31"} + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # response = html_response(conn, 200) + # assert response =~ "Date is not valid" + # end + + # test "bad date input: partial input", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => %{@morning | "month" => ""} + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # response = html_response(conn, 200) + # assert response =~ "Date is not valid" + # end + + # test "bad date input: corrupt day", %{conn: conn} do + # date_input = %{ + # "year" => "A", + # "month" => "B", + # "day" => "C", + # "hour" => "D", + # "minute" => "E", + # "am_pm" => "PM" + # } + + # params = %{ + # "date_time" => @system_time, + # "plan" => %{"from" => "from address", "to" => "to address", "date_time" => date_input} + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # response = html_response(conn, 200) + # assert response =~ "Date is not valid" + # end + + # test "bad date input: too far in future", %{conn: conn} do + # end_date = Timex.shift(Schedules.Repo.end_of_rating(), days: 1) + + # end_date_as_params = %{ + # "month" => Integer.to_string(end_date.month), + # "day" => Integer.to_string(end_date.day), + # "year" => Integer.to_string(end_date.year), + # "hour" => "12", + # "minute" => "15", + # "am_pm" => "PM" + # } + + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => end_date_as_params, + # "time" => "depart" + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # response = html_response(conn, 200) + # assert Map.get(conn.assigns, :plan_error) == [:too_future] + # assert response =~ "Date is too far in the future" + + # expected = + # [:too_future] + # |> DotcomWeb.TripPlanView.plan_error_description() + # |> IO.iodata_to_binary() + + # assert response =~ expected + # end + + # test "bad date input: date in past", %{conn: conn} do + # past_date = + # @system_time + # |> Timex.parse!("{ISO:Extended}") + # |> Timex.shift(days: -10) + + # past_date_as_params = %{ + # "month" => Integer.to_string(past_date.month), + # "day" => Integer.to_string(past_date.day), + # "year" => Integer.to_string(past_date.year), + # "hour" => "12", + # "minute" => "15", + # "am_pm" => "PM" + # } + + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => past_date_as_params, + # "time" => "depart" + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # response = html_response(conn, 200) + # assert Map.get(conn.assigns, :plan_error) == [:past] + # assert response =~ "Date is in the past" + # end + + # test "handles missing date and time params, using today's values if they are missing", + # %{conn: conn} do + # wrong_datetime_params = %{ + # "year" => "2017", + # "day" => "2", + # "hour" => "9", + # "am_pm" => "AM" + # } + + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => wrong_datetime_params + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert html_response(conn, 200) + # end + + # test "handles non-existing date and time params, using today's values", + # %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => %{} + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert html_response(conn, 200) + # end + + # test "does not need to default date and time params as they are present", + # %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => @morning + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # assert html_response(conn, 200) + # end + + # test "good date input: date within service date of end of rating", %{conn: conn} do + # # after midnight but before end of service on last day of rating + # # should still be inside of the rating + + # date = Timex.shift(conn.assigns.end_of_rating, days: 1) + + # date_params = %{ + # "month" => Integer.to_string(date.month), + # "day" => Integer.to_string(date.day), + # "year" => Integer.to_string(date.year), + # "hour" => "12", + # "minute" => "15", + # "am_pm" => "AM" + # } + + # params = %{ + # "date_time" => @system_time, + # "plan" => %{"from" => "from address", "to" => "to address", "date_time" => date_params} + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + + # response = html_response(conn, 200) + # assert Map.get(conn.assigns, :plan_error) == [] + # refute response =~ "Date is too far in the future" + # refute response =~ "Date is not valid" + # end + + # test "hour and minute are processed correctly when provided as single digits", %{conn: conn} do + # params = %{ + # "date_time" => @system_time, + # "plan" => %{ + # "from" => "from address", + # "to" => "to address", + # "date_time" => %{@after_hours | "hour" => "1", "minute" => "1"}, + # "time" => "depart" + # } + # } + + # conn = get(conn, trip_plan_path(conn, :index, params)) + # response = html_response(conn, 200) + # assert Map.get(conn.assigns, :plan_error) == [] + # refute response =~ "Date is not valid" + # end + # end + + # describe "/from/ address path" do + # test "gets a valid address in the 'from' field", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :from, "Boston Common")) + + # assert conn.assigns.query.from.name == "Boston Common" + # end + + # test "uses expected values when addres is formatted latitutde,longitude,stopName", %{ + # conn: conn + # } do + # conn = get(conn, trip_plan_path(conn, :from, "42.395428,-71.142483,Cobbs Corner, Canton")) + + # assert html_response(conn, 200) + # assert conn.assigns.query.from.name == "Cobbs Corner, Canton" + # assert conn.assigns.query.from.latitude == 42.395428 + # assert conn.assigns.query.from.longitude == -71.142483 + # end + + # test "is unable to get address so it redirects to index", %{conn: conn} do + # expect(LocationService.Mock, :geocode, fn _ -> + # {:error, :something} + # end) + + # conn = get(conn, trip_plan_path(conn, :from, "Atlantis")) + # assert html_response(conn, 302) =~ "/trip-planner" + # end + + # test "when 'plan' is part of the parameters, it redirects to the usual trip planner", %{ + # conn: conn + # } do + # plan_params = %{"plan" => %{"from" => "from address", "to" => "to address"}} + + # conn = + # get( + # conn, + # trip_plan_path(conn, :from, "Address", plan_params) + # ) + + # assert redirected_to(conn) == trip_plan_path(conn, :index, plan_params) + # end + # end + + # describe "/to/ address path" do + # test "gets a valid address in the 'to' field", %{conn: conn} do + # conn = get(conn, trip_plan_path(conn, :to, "Boston Common")) + # assert conn.assigns.query.to.name == "Boston Common" + # end + + # test "uses expected values when address is formatted latitutde,longitude,stopName", %{ + # conn: conn + # } do + # conn = get(conn, trip_plan_path(conn, :to, "42.395428,-71.142483,Cobbs Corner, Canton")) + + # assert html_response(conn, 200) + # assert conn.assigns.query.to.name == "Cobbs Corner, Canton" + # assert conn.assigns.query.to.latitude == 42.395428 + # assert conn.assigns.query.to.longitude == -71.142483 + # end + + # test "is unable to get address so it redirects to index", %{conn: conn} do + # expect(LocationService.Mock, :geocode, fn _ -> + # {:error, :something} + # end) + + # conn = get(conn, trip_plan_path(conn, :to, "Atlantis")) + # assert html_response(conn, 302) =~ "/trip-planner" + # end + + # test "when 'plan' is part of the parameters, it redirects to the usual trip planner", %{ + # conn: conn + # } do + # plan_params = %{"plan" => %{"from" => "from address", "to" => "to address"}} + + # conn = + # get( + # conn, + # trip_plan_path(conn, :to, "Address", plan_params) + # ) + + # assert redirected_to(conn) == trip_plan_path(conn, :index, plan_params) + # end + # end end From 7ff619e77d4f2a0a81b418332490261a194883ba Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Mon, 6 Jan 2025 10:36:22 -0600 Subject: [PATCH 2/7] restore and remove --- .../controllers/places_controller.ex | 20 +- .../controllers/trip_plan_controller.ex | 309 -------- lib/dotcom_web/controllers/vote_controller.ex | 130 ++-- lib/dotcom_web/router.ex | 2 +- .../templates/layout/live.html.heex | 2 +- lib/dotcom_web/views/vote_view.ex | 3 +- .../controllers/trip_plan_controller_test.exs | 720 ------------------ 7 files changed, 78 insertions(+), 1108 deletions(-) delete mode 100644 lib/dotcom_web/controllers/trip_plan_controller.ex delete mode 100644 test/dotcom_web/controllers/trip_plan_controller_test.exs diff --git a/lib/dotcom_web/controllers/places_controller.ex b/lib/dotcom_web/controllers/places_controller.ex index 931e0b2346..e997284c7c 100644 --- a/lib/dotcom_web/controllers/places_controller.ex +++ b/lib/dotcom_web/controllers/places_controller.ex @@ -155,16 +155,16 @@ defmodule DotcomWeb.PlacesController do Map.take(map, [:latitude, :longitude]) end - # vote_params = - # case map do - # %{formatted: formatted} -> - # map - # |> Map.take([:latitude, :longitude]) - # |> Map.put(:address, formatted) + vote_params = + case map do + %{formatted: formatted} -> + map + |> Map.take([:latitude, :longitude]) + |> Map.put(:address, formatted) - # _ -> - # %{} - # end + _ -> + %{} + end map |> Map.put_new(:urls, %{ @@ -177,7 +177,7 @@ defmodule DotcomWeb.PlacesController do params ), "transit-near-me" => transit_near_me_path(DotcomWeb.Endpoint, :index, params), - # "vote" => vote_path(DotcomWeb.Endpoint, :show, vote_params) + "vote" => vote_path(DotcomWeb.Endpoint, :show, vote_params) }) end diff --git a/lib/dotcom_web/controllers/trip_plan_controller.ex b/lib/dotcom_web/controllers/trip_plan_controller.ex deleted file mode 100644 index 1fac9a0593..0000000000 --- a/lib/dotcom_web/controllers/trip_plan_controller.ex +++ /dev/null @@ -1,309 +0,0 @@ -defmodule DotcomWeb.TripPlanController do - @moduledoc """ - Controller for trip plans. - """ - - # use DotcomWeb, :controller - - # require Logger - - # alias Dotcom.TripPlan.{ - # Itinerary, - # ItineraryRowList, - # Leg, - # NamedPosition, - # PersonalDetail, - # Query, - # RelatedLink, - # TransitDetail - # } - - # alias Dotcom.TripPlan.Map, as: TripPlanMap - # alias Routes.Route - - # @location_service Application.compile_env!(:dotcom, :location_service) - - # @type route_map :: %{optional(Route.id_t()) => Route.t()} - # @type route_mapper :: (Route.id_t() -> Route.t() | nil) - - # plug(:assign_initial_map) - # plug(:breadcrumbs) - # plug(:modes) - # plug(:wheelchair) - # plug(:meta_description) - # plug(:assign_params) - - # def index(conn, %{"plan" => %{"to" => _to, "from" => _fr} = plan}) do - # conn - # |> assign(:expanded, conn.query_params["expanded"]) - # |> render_plan(plan) - # end - - # def index(conn, _params) do - # render(conn, :index) - # end - - # def from(conn, %{"plan" => _plan} = params) do - # redirect(conn, to: trip_plan_path(conn, :index, Map.delete(params, "address"))) - # end - - # def from(conn, %{ - # "address" => address - # }) do - # if String.match?(address, ~r/^(\-?\d+(\.\d+)?),(\-?\d+(\.\d+)?),.*$/) do - # [latitude, longitude, name] = String.split(address, ",", parts: 3) - # # Avoid extra geocode call, just use these coordinates - # destination = %NamedPosition{ - # latitude: String.to_float(latitude), - # longitude: String.to_float(longitude), - # name: name, - # stop: nil - # } - - # do_from(conn, destination) - # else - # updated_address = check_address(address) - - # case @location_service.geocode(updated_address) do - # {:ok, [geocoded_from | _]} -> - # do_from(conn, NamedPosition.new(geocoded_from)) - - # _ -> - # # redirect to the initial index page - # redirect(conn, to: trip_plan_path(conn, :index)) - # end - # end - # end - - # defp do_from(conn, destination) do - # # build a default query with a pre-filled 'from' field: - # query = %Query{ - # from: destination, - # to: {:error, :unknown}, - # time: {:error, :unknown} - # } - - # now = Util.now() - - # # build map information for a single leg with the 'from' field: - # map_data = - # TripPlanMap.itinerary_map([ - # %Leg{ - # from: destination, - # to: nil, - # mode: %PersonalDetail{}, - # start: now, - # stop: now - # } - # ]) - - # %{markers: [marker]} = map_data - # from_marker = %{marker | id: "B"} - # map_info_for_from_destination = %{map_data | markers: [from_marker]} - - # conn - # |> assign(:query, query) - # |> assign(:map_data, map_info_for_from_destination) - # |> render(:index) - # end - - # def to(conn, %{"plan" => _plan} = params) do - # redirect(conn, to: trip_plan_path(conn, :index, Map.delete(params, "address"))) - # end - - # def to(conn, %{ - # "address" => address - # }) do - # if String.match?(address, ~r/^(\-?\d+(\.\d+)?),(\-?\d+(\.\d+)?),.*$/) do - # [latitude, longitude, name] = String.split(address, ",", parts: 3) - # # Avoid extra geocode call, just use these coordinates - # destination = %NamedPosition{ - # latitude: String.to_float(latitude), - # longitude: String.to_float(longitude), - # name: name, - # stop: nil - # } - - # do_to(conn, destination) - # else - # updated_address = check_address(address) - - # case @location_service.geocode(updated_address) do - # {:ok, [geocoded_to | _]} -> - # do_to(conn, NamedPosition.new(geocoded_to)) - - # _ -> - # # redirect to the initial index page - # redirect(conn, to: trip_plan_path(conn, :index)) - # end - # end - # end - - # defp do_to(conn, destination) do - # # build a default query with a pre-filled 'to' field: - # query = %Query{ - # to: destination, - # time: {:error, :unknown}, - # from: {:error, :unknown} - # } - - # now = Util.now() - - # # build map information for a single leg with the 'to' field: - # map_data = - # TripPlanMap.itinerary_map([ - # %Leg{ - # from: nil, - # to: destination, - # mode: %PersonalDetail{}, - # start: now, - # stop: now - # } - # ]) - - # %{markers: [marker]} = map_data - # to_marker = %{marker | id: "B"} - # map_info_for_to_destination = %{map_data | markers: [to_marker]} - - # conn - # |> assign(:query, query) - # |> assign(:map_data, map_info_for_to_destination) - # |> render(:index) - # end - - # defp assign_params(conn, _) do - # conn - # |> assign(:chosen_date_time, conn.params["plan"]["date_time"]) - # |> assign(:chosen_time, conn.params["plan"]["time"]) - # end - - # @spec check_address(String.t()) :: String.t() - # defp check_address(address) do - # # address can be a String containing "lat,lon" so we check for that case - - # [lat, lon] = - # case String.split(address, ",", parts: 2) do - # [lat, lon] -> [lat, lon] - # _ -> ["error", "error"] - # end - - # if Float.parse(lat) == :error || Float.parse(lon) == :error do - # address - # else - # {parsed_lat, _} = Float.parse(lat) - # {parsed_lon, _} = Float.parse(lon) - - # case @location_service.reverse_geocode(parsed_lat, parsed_lon) do - # {:ok, [first | _]} -> - # first.formatted - - # _ -> - # "#{lat}, #{lon}" - # end - # end - # end - - # defp get_route(link) do - # if is_bitstring(link.text) do - # link.text - # else - # link.text |> List.to_string() - # end - # end - - # defp filter_duplicate_links(related_links) do - # Enum.map(related_links, fn x -> Enum.uniq_by(x, fn y -> get_route(y) end) end) - # end - - # @spec render_plan(Plug.Conn.t(), map) :: Plug.Conn.t() - # defp render_plan(conn, plan_params) do - # query = - # Query.from_query( - # plan_params, - # now: conn.assigns.date_time, - # end_of_rating: Map.get(conn.assigns, :end_of_rating, Schedules.Repo.end_of_rating()) - # ) - - # itineraries = - # query - # |> Query.get_itineraries() - - # itinerary_row_lists = itinerary_row_lists(itineraries, plan_params) - - # conn - # |> render( - # query: query, - # itineraries: itineraries, - # plan_error: MapSet.to_list(query.errors), - # routes: Enum.map(itineraries, &routes_for_itinerary(&1)), - # itinerary_maps: Enum.map(itineraries, &TripPlanMap.itinerary_map(&1)), - # related_links: - # filter_duplicate_links(Enum.map(itineraries, &RelatedLink.links_for_itinerary(&1))), - # itinerary_row_lists: itinerary_row_lists - # ) - # end - - # @spec itinerary_row_lists([Itinerary.t()], map) :: [ItineraryRowList.t()] - # defp itinerary_row_lists(itineraries, plan) do - # Enum.map(itineraries, &ItineraryRowList.from_itinerary(&1, to_and_from(plan))) - # end - - # @spec assign_initial_map(Plug.Conn.t(), any()) :: Plug.Conn.t() - # def assign_initial_map(conn, _opts) do - # conn - # |> assign(:map_data, TripPlanMap.initial_map_data()) - # end - - # @spec modes(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - # def modes(%Plug.Conn{params: %{"plan" => %{"modes" => modes}}} = conn, _) do - # assign( - # conn, - # :modes, - # Map.new(modes, fn {mode, active?} -> {String.to_existing_atom(mode), active? === "true"} end) - # ) - # end - - # def modes(%Plug.Conn{} = conn, _) do - # assign( - # conn, - # :modes, - # %{subway: true, bus: true, commuter_rail: true, ferry: true} - # ) - # end - - # @spec breadcrumbs(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - # defp breadcrumbs(conn, _) do - # assign(conn, :breadcrumbs, [Breadcrumb.build("Trip Planner")]) - # end - - # @spec wheelchair(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() - # def wheelchair(%Plug.Conn{params: %{"plan" => plan_params}} = conn, _) do - # assign(conn, :wheelchair, get_in(plan_params, ["wheelchair"]) === "true") - # end - - # # Initialize to checked state for trip plan accessibility - # def wheelchair(%Plug.Conn{} = conn, _) do - # assign(conn, :wheelchair, true) - # end - - # @spec routes_for_itinerary(Itinerary.t()) :: [Route.t()] - # defp routes_for_itinerary(itinerary) do - # itinerary.legs - # |> Enum.filter(&match?(%TransitDetail{}, &1.mode)) - # |> Enum.map(& &1.mode.route) - # end - - # @spec to_and_from(map) :: [to: String.t() | nil, from: String.t() | nil] - # def to_and_from(plan) do - # [to: Map.get(plan, "to"), from: Map.get(plan, "from")] - # end - - # defp meta_description(conn, _) do - # conn - # |> assign( - # :meta_description, - # "Plan a trip on public transit in the Greater Boston region with directions " <> - # "and suggestions based on real-time data." - # ) - # end -end diff --git a/lib/dotcom_web/controllers/vote_controller.ex b/lib/dotcom_web/controllers/vote_controller.ex index e887c9acea..0283175d76 100644 --- a/lib/dotcom_web/controllers/vote_controller.ex +++ b/lib/dotcom_web/controllers/vote_controller.ex @@ -3,81 +3,81 @@ defmodule DotcomWeb.VoteController do Handles rendering the vote widget """ - # use DotcomWeb, :controller + use DotcomWeb, :controller - # import DotcomWeb.ViewHelpers, only: [cms_static_page_path: 2] + import DotcomWeb.ViewHelpers, only: [cms_static_page_path: 2] - # plug(:meta_description) - # plug(:clear_polling_results) + plug(:meta_description) + plug(:clear_polling_results) - # def show( - # conn, - # %{"address" => address, "latitude" => latitude, "longitude" => longitude} = _params - # ) do - # google_api_key = Application.get_env(:dotcom, :google_api_key) + def show( + conn, + %{"address" => address, "latitude" => latitude, "longitude" => longitude} = _params + ) do + google_api_key = Application.get_env(:dotcom, :google_api_key) - # response = - # Req.get("https://www.googleapis.com/civicinfo/v2/voterinfo", - # params: [ - # key: google_api_key, - # electionId: "9000", - # address: address - # ] - # ) + response = + Req.get("https://www.googleapis.com/civicinfo/v2/voterinfo", + params: [ + key: google_api_key, + electionId: "9000", + address: address + ] + ) - # conn = - # case response do - # {:ok, %{body: %{"pollingLocations" => [polling_location | _]}}} -> - # polling_location_name = Recase.to_title(polling_location["address"]["locationName"]) + conn = + case response do + {:ok, %{body: %{"pollingLocations" => [polling_location | _]}}} -> + polling_location_name = Recase.to_title(polling_location["address"]["locationName"]) - # params = %{ - # "plan" => %{ - # "from_latitude" => latitude, - # "from_longitude" => longitude, - # "from" => address, - # "to_latitude" => polling_location["latitude"], - # "to_longitude" => polling_location["longitude"], - # "to" => polling_location_name - # } - # } + params = %{ + "plan" => %{ + "from_latitude" => latitude, + "from_longitude" => longitude, + "from" => address, + "to_latitude" => polling_location["latitude"], + "to_longitude" => polling_location["longitude"], + "to" => polling_location_name + } + } - # conn - # |> assign(:polling_location, polling_location) - # |> assign(:polling_location_name, polling_location_name) - # |> assign(:trip_plan_path, trip_plan_path(DotcomWeb.Endpoint, :index, params)) + conn + |> assign(:polling_location, polling_location) + |> assign(:polling_location_name, polling_location_name) + |> assign(:trip_plan_path, "/trip-planner#{URI.encode_query(params)}") - # _ -> - # conn |> assign(:polling_error, true) - # end + _ -> + conn |> assign(:polling_error, true) + end - # conn - # |> assign(:should_scroll, true) - # |> assign(:breadcrumbs, [ - # Breadcrumb.build("Take the T to Vote", cms_static_page_path(conn, "/vote")) - # ]) - # |> render("show.html") - # end + conn + |> assign(:should_scroll, true) + |> assign(:breadcrumbs, [ + Breadcrumb.build("Take the T to Vote", cms_static_page_path(conn, "/vote")) + ]) + |> render("show.html") + end - # def show(conn, _params) do - # conn - # |> assign(:breadcrumbs, [ - # Breadcrumb.build("Vote", cms_static_page_path(conn, "/vote")) - # ]) - # |> render("show.html") - # end + def show(conn, _params) do + conn + |> assign(:breadcrumbs, [ + Breadcrumb.build("Vote", cms_static_page_path(conn, "/vote")) + ]) + |> render("show.html") + end - # defp meta_description(conn, _) do - # conn - # |> assign( - # :meta_description, - # "Tuesday, November 5 is the last day to vote in the 2024 general election. Use the T to get to your polling location." - # ) - # end + defp meta_description(conn, _) do + conn + |> assign( + :meta_description, + "Tuesday, November 5 is the last day to vote in the 2024 general election. Use the T to get to your polling location." + ) + end - # defp clear_polling_results(conn, _) do - # conn - # |> assign(:polling_location, nil) - # |> assign(:polling_error, false) - # |> assign(:should_scroll, false) - # end + defp clear_polling_results(conn, _) do + conn + |> assign(:polling_location, nil) + |> assign(:polling_error, false) + |> assign(:should_scroll, false) + end end diff --git a/lib/dotcom_web/router.ex b/lib/dotcom_web/router.ex index a2dcd73a7f..f53865d67a 100644 --- a/lib/dotcom_web/router.ex +++ b/lib/dotcom_web/router.ex @@ -237,7 +237,7 @@ defmodule DotcomWeb.Router do post("/search/query", SearchController, :query) post("/search/click", SearchController, :click) get("/bus-stop-changes", BusStopChangeController, :show) - # get("/vote", VoteController, :show) + get("/vote", VoteController, :show) end scope "/", DotcomWeb do diff --git a/lib/dotcom_web/templates/layout/live.html.heex b/lib/dotcom_web/templates/layout/live.html.heex index d4b5ad37e3..01eded9c98 100644 --- a/lib/dotcom_web/templates/layout/live.html.heex +++ b/lib/dotcom_web/templates/layout/live.html.heex @@ -1,3 +1,3 @@
{@inner_content} -
\ No newline at end of file + diff --git a/lib/dotcom_web/views/vote_view.ex b/lib/dotcom_web/views/vote_view.ex index f13877a231..e05f122a07 100644 --- a/lib/dotcom_web/views/vote_view.ex +++ b/lib/dotcom_web/views/vote_view.ex @@ -2,6 +2,5 @@ defmodule DotcomWeb.VoteView do @moduledoc """ View for the vote widget """ - - # use DotcomWeb, :view + use DotcomWeb, :view end diff --git a/test/dotcom_web/controllers/trip_plan_controller_test.exs b/test/dotcom_web/controllers/trip_plan_controller_test.exs deleted file mode 100644 index 547fe4b681..0000000000 --- a/test/dotcom_web/controllers/trip_plan_controller_test.exs +++ /dev/null @@ -1,720 +0,0 @@ -defmodule DotcomWeb.TripPlanControllerTest do - # use DotcomWeb.ConnCase, async: true - - # alias Dotcom.TripPlan.{Itinerary, PersonalDetail, Query, TransitDetail} - # alias Fares.Fare - - # import Test.Support.Factories.LocationService.LocationService - - # doctest DotcomWeb.TripPlanController - - # import Mox - - # @system_time "2017-01-01T12:20:00-05:00" - # @morning %{ - # "year" => "2017", - # "month" => "1", - # "day" => "2", - # "hour" => "9", - # "minute" => "30", - # "am_pm" => "AM" - # } - # @afternoon %{ - # "year" => "2017", - # "month" => "1", - # "day" => "2", - # "hour" => "5", - # "minute" => "30", - # "am_pm" => "PM" - # } - # @after_hours %{ - # "year" => "2017", - # "month" => "1", - # "day" => "2", - # "hour" => "3", - # "minute" => "00", - # "am_pm" => "AM" - # } - # @modes %{"subway" => "true", "commuter_rail" => "true", "bus" => "false", "ferry" => "false"} - - # @good_params %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => @afternoon, - # "time" => "depart", - # "modes" => @modes, - # "wheelchair" => "true" - # } - # } - - # @bad_params %{ - # "date_time" => @system_time, - # "plan" => %{"from" => "no results", "to" => "too many results", "date_time" => @afternoon} - # } - - # setup :verify_on_exit! - - # setup do - # stub(MBTA.Api.Mock, :get_json, fn "/schedules/", [route: "Red", date: "1970-01-01"] -> - # {:error, - # [ - # %JsonApi.Error{ - # code: "no_service", - # source: %{ - # "parameter" => "date" - # }, - # detail: "The current rating does not describe service on that date.", - # meta: %{ - # "end_date" => "2024-06-15", - # "start_date" => "2024-05-10", - # "version" => "Spring 2024, 2024-05-17T21:10:15+00:00, version D" - # } - # } - # ]} - # end) - - # stub(OpenTripPlannerClient.Mock, :plan, fn _from, _to, _opts -> - # {:ok, %OpenTripPlannerClient.Plan{itineraries: []}} - # end) - - # stub(LocationService.Mock, :geocode, fn name -> - # {:ok, build_list(2, :address, %{formatted: name})} - # end) - - # stub(Stops.Repo.Mock, :get_parent, fn _ -> - # %Stops.Stop{} - # end) - - # cache = Application.get_env(:dotcom, :cache) - # cache.flush() - - # conn = default_conn() - - # end_of_rating = - # @system_time - # |> Timex.parse!("{ISO:Extended}") - # |> Timex.shift(months: 3) - # |> DateTime.to_date() - - # {:ok, conn: assign(conn, :end_of_rating, end_of_rating)} - # end - - # describe "index without params" do - # test "renders index.html", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index)) - # assert html_response(conn, 200) =~ "Trip Planner" - # end - - # test "assigns initial map data", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index)) - # assert conn.assigns.map_data - # end - - # test "sets a custom meta description", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index)) - # assert conn.assigns.meta_description - # end - # end - - # describe "index with params" do - # test "renders the query plan", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - # response = html_response(conn, 200) - # assert response =~ "Trip Planner" - # assert %Query{} = conn.assigns.query - # assert conn.assigns.itineraries - # assert conn.assigns.routes - # assert conn.assigns.itinerary_maps - # assert conn.assigns.related_links - # end - - # test "uses current location to render a query plan", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "Your current location", - # "from_latitude" => "42.3428", - # "from_longitude" => "-71.0857", - # "to" => "to address", - # "to_latitude" => "", - # "to_longitude" => "", - # "date_time" => @morning, - # "modes" => @modes - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - - # assert html_response(conn, 200) =~ "Trip Planner" - # assert %Query{} = conn.assigns.query - # end - - # test "sets hidden inputs for lat/lng", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "from_latitude" => "1", - # "from_longitude" => "2", - # "to" => "to address", - # "to_latitude" => "3", - # "to_longitude" => "4", - # "date_time" => @morning, - # "modes" => @modes - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - - # resp = html_response(conn, 200) - # assert from_latitude = Floki.find(resp, "#from_latitude") - # assert from_longitude = Floki.find(resp, "#from_longitude") - # assert to_latitude = Floki.find(resp, "#to_latitude") - # assert to_longitude = Floki.find(resp, "#to_longitude") - # assert List.first(Floki.attribute(from_latitude, "value")) == "1.0" - # assert List.first(Floki.attribute(from_longitude, "value")) == "2.0" - # assert List.first(Floki.attribute(to_latitude, "value")) == "3.0" - # assert List.first(Floki.attribute(to_longitude, "value")) == "4.0" - # end - - # test "assigns.mode is a map of parsed mode state", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "Your current location", - # "from_latitude" => "42.3428", - # "from_longitude" => "-71.0857", - # "to" => "to address", - # "to_latitude" => "", - # "to_longitude" => "", - # "date_time" => @morning, - # "modes" => @modes - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - - # assert html_response(conn, 200) =~ "Trip Planner" - # assert conn.assigns.modes == %{subway: true, commuter_rail: true, bus: false, ferry: false} - # assert %Query{} = conn.assigns.query - # end - - # test "assigns.wheelchair uses value provided in params", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "Your current location", - # "from_latitude" => "42.3428", - # "from_longitude" => "-71.0857", - # "to" => "to address", - # "to_latitude" => "", - # "to_longitude" => "", - # "date_time" => @morning, - # "modes" => @modes, - # "wheelchair" => "true" - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - - # assert html_response(conn, 200) =~ "Trip Planner" - # assert conn.assigns.wheelchair == true - # end - - # test "can use the old date time format", %{conn: conn} do - # old_dt_format = Map.delete(@afternoon, "am_pm") - - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from_address", - # "from_latitude" => "", - # "from_longitude" => "", - # "to" => "to address", - # "to_latitude" => "", - # "to_longitude" => "", - # "date_time" => old_dt_format, - # "mode" => @modes - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert html_response(conn, 200) - # end - - # test "each map url has a path color", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - # for {map_data, static_map} <- conn.assigns.itinerary_maps do - # assert static_map =~ "color" - - # for path <- map_data.polylines do - # assert path.color - # end - # end - # end - - # test "renders a geocoding error", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @bad_params)) - # response = html_response(conn, 200) - # assert response =~ "Trip Planner" - # # shows error styling on location input with "required" label - # assert response =~ "(Required)" - # assert %Query{} = conn.assigns.query - # end - - # test "assigns maps for each itinerary", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - # assert conn.assigns.itinerary_maps - # end - - # test "gets routes from each itinerary", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - # assert conn.assigns.routes - - # for routes_for_itinerary <- conn.assigns.routes do - # assert length(routes_for_itinerary) > 0 - # end - # end - - # test "assigns an ItineraryRowList for each itinerary", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - # assert conn.assigns.itinerary_row_lists - # end - - # test "adds fare data to each transit leg of each itinerary", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - # assert Enum.all?(conn.assigns.itineraries, fn itinerary -> - # Enum.all?(itinerary.legs, fn leg -> - # match?(%PersonalDetail{}, leg.mode) || - # match?( - # %TransitDetail{ - # fares: %{ - # highest_one_way_fare: %Fares.Fare{}, - # lowest_one_way_fare: %Fares.Fare{}, - # reduced_one_way_fare: %Fares.Fare{} - # } - # }, - # leg.mode - # ) - # end) - # end) - # end - - # test "returns all nil fares when there is not enough information", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - # for itinerary <- conn.assigns.itineraries do - # for leg <- itinerary.legs do - # if Dotcom.TripPlan.Leg.transit?(leg) do - # assert leg.mode.fares == %{ - # highest_one_way_fare: nil, - # lowest_one_way_fare: nil, - # reduced_one_way_fare: nil - # } - # end - # end - # end - # end - - # test "adds monthly pass data to each itinerary", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :index, @good_params)) - - # assert Enum.all?(conn.assigns.itineraries, fn itinerary -> - # %Itinerary{passes: %{base_month_pass: %Fare{}, recommended_month_pass: %Fare{}}} = - # itinerary - # end) - # end - - # test "renders an error if longitude and latitude from both addresses are the same", %{ - # conn: conn - # } do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from_latitude" => "90", - # "to_latitude" => "90", - # "from_longitude" => "50", - # "to_longitude" => "50", - # "date_time" => @afternoon, - # "from" => "from St", - # "to" => "from Street" - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert conn.assigns.plan_error == [:same_address] - # assert html_response(conn, 200) - # assert html_response(conn, 200) =~ "two different locations" - # end - - # test "doesn't render an error if longitudes and latitudes are unique", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from_latitude" => "90", - # "to_latitude" => "90.5", - # "from_longitude" => "50.5", - # "to_longitude" => "50", - # "date_time" => @afternoon, - # "from" => "from St", - # "to" => "from Street" - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert conn.assigns.plan_error == [] - # assert html_response(conn, 200) - # end - - # test "renders an error if to and from address are the same", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from", - # "to" => "from", - # "date_time" => @afternoon - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert conn.assigns.plan_error == [:same_address] - # assert html_response(conn, 200) - # assert html_response(conn, 200) =~ "two different locations" - # end - - # test "doesn't render an error if to and from address are unique", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from", - # "to" => "to", - # "date_time" => @afternoon - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert conn.assigns.plan_error == [] - # assert html_response(conn, 200) - # end - - # test "handles empty lat/lng", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from", - # "to" => "from", - # "to_latitude" => "", - # "to_longitude" => "", - # "from_latitude" => "", - # "from_longitude" => "", - # "date_time" => @afternoon - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert conn.assigns.plan_error == [:same_address] - # assert html_response(conn, 200) - # assert html_response(conn, 200) =~ "two different locations" - # end - - # test "bad date input: fictional day", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => %{@morning | "month" => "6", "day" => "31"} - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # response = html_response(conn, 200) - # assert response =~ "Date is not valid" - # end - - # test "bad date input: partial input", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => %{@morning | "month" => ""} - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # response = html_response(conn, 200) - # assert response =~ "Date is not valid" - # end - - # test "bad date input: corrupt day", %{conn: conn} do - # date_input = %{ - # "year" => "A", - # "month" => "B", - # "day" => "C", - # "hour" => "D", - # "minute" => "E", - # "am_pm" => "PM" - # } - - # params = %{ - # "date_time" => @system_time, - # "plan" => %{"from" => "from address", "to" => "to address", "date_time" => date_input} - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # response = html_response(conn, 200) - # assert response =~ "Date is not valid" - # end - - # test "bad date input: too far in future", %{conn: conn} do - # end_date = Timex.shift(Schedules.Repo.end_of_rating(), days: 1) - - # end_date_as_params = %{ - # "month" => Integer.to_string(end_date.month), - # "day" => Integer.to_string(end_date.day), - # "year" => Integer.to_string(end_date.year), - # "hour" => "12", - # "minute" => "15", - # "am_pm" => "PM" - # } - - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => end_date_as_params, - # "time" => "depart" - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # response = html_response(conn, 200) - # assert Map.get(conn.assigns, :plan_error) == [:too_future] - # assert response =~ "Date is too far in the future" - - # expected = - # [:too_future] - # |> DotcomWeb.TripPlanView.plan_error_description() - # |> IO.iodata_to_binary() - - # assert response =~ expected - # end - - # test "bad date input: date in past", %{conn: conn} do - # past_date = - # @system_time - # |> Timex.parse!("{ISO:Extended}") - # |> Timex.shift(days: -10) - - # past_date_as_params = %{ - # "month" => Integer.to_string(past_date.month), - # "day" => Integer.to_string(past_date.day), - # "year" => Integer.to_string(past_date.year), - # "hour" => "12", - # "minute" => "15", - # "am_pm" => "PM" - # } - - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => past_date_as_params, - # "time" => "depart" - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # response = html_response(conn, 200) - # assert Map.get(conn.assigns, :plan_error) == [:past] - # assert response =~ "Date is in the past" - # end - - # test "handles missing date and time params, using today's values if they are missing", - # %{conn: conn} do - # wrong_datetime_params = %{ - # "year" => "2017", - # "day" => "2", - # "hour" => "9", - # "am_pm" => "AM" - # } - - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => wrong_datetime_params - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert html_response(conn, 200) - # end - - # test "handles non-existing date and time params, using today's values", - # %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => %{} - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert html_response(conn, 200) - # end - - # test "does not need to default date and time params as they are present", - # %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => @morning - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # assert html_response(conn, 200) - # end - - # test "good date input: date within service date of end of rating", %{conn: conn} do - # # after midnight but before end of service on last day of rating - # # should still be inside of the rating - - # date = Timex.shift(conn.assigns.end_of_rating, days: 1) - - # date_params = %{ - # "month" => Integer.to_string(date.month), - # "day" => Integer.to_string(date.day), - # "year" => Integer.to_string(date.year), - # "hour" => "12", - # "minute" => "15", - # "am_pm" => "AM" - # } - - # params = %{ - # "date_time" => @system_time, - # "plan" => %{"from" => "from address", "to" => "to address", "date_time" => date_params} - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - - # response = html_response(conn, 200) - # assert Map.get(conn.assigns, :plan_error) == [] - # refute response =~ "Date is too far in the future" - # refute response =~ "Date is not valid" - # end - - # test "hour and minute are processed correctly when provided as single digits", %{conn: conn} do - # params = %{ - # "date_time" => @system_time, - # "plan" => %{ - # "from" => "from address", - # "to" => "to address", - # "date_time" => %{@after_hours | "hour" => "1", "minute" => "1"}, - # "time" => "depart" - # } - # } - - # conn = get(conn, trip_plan_path(conn, :index, params)) - # response = html_response(conn, 200) - # assert Map.get(conn.assigns, :plan_error) == [] - # refute response =~ "Date is not valid" - # end - # end - - # describe "/from/ address path" do - # test "gets a valid address in the 'from' field", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :from, "Boston Common")) - - # assert conn.assigns.query.from.name == "Boston Common" - # end - - # test "uses expected values when addres is formatted latitutde,longitude,stopName", %{ - # conn: conn - # } do - # conn = get(conn, trip_plan_path(conn, :from, "42.395428,-71.142483,Cobbs Corner, Canton")) - - # assert html_response(conn, 200) - # assert conn.assigns.query.from.name == "Cobbs Corner, Canton" - # assert conn.assigns.query.from.latitude == 42.395428 - # assert conn.assigns.query.from.longitude == -71.142483 - # end - - # test "is unable to get address so it redirects to index", %{conn: conn} do - # expect(LocationService.Mock, :geocode, fn _ -> - # {:error, :something} - # end) - - # conn = get(conn, trip_plan_path(conn, :from, "Atlantis")) - # assert html_response(conn, 302) =~ "/trip-planner" - # end - - # test "when 'plan' is part of the parameters, it redirects to the usual trip planner", %{ - # conn: conn - # } do - # plan_params = %{"plan" => %{"from" => "from address", "to" => "to address"}} - - # conn = - # get( - # conn, - # trip_plan_path(conn, :from, "Address", plan_params) - # ) - - # assert redirected_to(conn) == trip_plan_path(conn, :index, plan_params) - # end - # end - - # describe "/to/ address path" do - # test "gets a valid address in the 'to' field", %{conn: conn} do - # conn = get(conn, trip_plan_path(conn, :to, "Boston Common")) - # assert conn.assigns.query.to.name == "Boston Common" - # end - - # test "uses expected values when address is formatted latitutde,longitude,stopName", %{ - # conn: conn - # } do - # conn = get(conn, trip_plan_path(conn, :to, "42.395428,-71.142483,Cobbs Corner, Canton")) - - # assert html_response(conn, 200) - # assert conn.assigns.query.to.name == "Cobbs Corner, Canton" - # assert conn.assigns.query.to.latitude == 42.395428 - # assert conn.assigns.query.to.longitude == -71.142483 - # end - - # test "is unable to get address so it redirects to index", %{conn: conn} do - # expect(LocationService.Mock, :geocode, fn _ -> - # {:error, :something} - # end) - - # conn = get(conn, trip_plan_path(conn, :to, "Atlantis")) - # assert html_response(conn, 302) =~ "/trip-planner" - # end - - # test "when 'plan' is part of the parameters, it redirects to the usual trip planner", %{ - # conn: conn - # } do - # plan_params = %{"plan" => %{"from" => "from address", "to" => "to address"}} - - # conn = - # get( - # conn, - # trip_plan_path(conn, :to, "Address", plan_params) - # ) - - # assert redirected_to(conn) == trip_plan_path(conn, :index, plan_params) - # end - # end -end From 0e6acc5fb0d976bc38728388a29e99e8ce5d2c88 Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Mon, 6 Jan 2025 10:46:30 -0600 Subject: [PATCH 3/7] fix vote paths --- lib/dotcom_web/templates/vote/show.html.heex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dotcom_web/templates/vote/show.html.heex b/lib/dotcom_web/templates/vote/show.html.heex index 67f41d4321..337089fca1 100644 --- a/lib/dotcom_web/templates/vote/show.html.heex +++ b/lib/dotcom_web/templates/vote/show.html.heex @@ -42,7 +42,7 @@ {@polling_location["address"]["city"]}, {@polling_location["address"]["state"]} {@polling_location["address"]["zip"]} - + Plan your trip @@ -56,7 +56,7 @@ Secretary of State's official site to find your polling place, and then use the - + MBTA Trip Planner to plan your trip. From 2ccef3fa00e07464dda46803274abd4544f6795c Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Mon, 6 Jan 2025 11:08:07 -0600 Subject: [PATCH 4/7] tests --- test/dotcom_web/live/trip_planner_test.exs | 34 +++++++--------------- test/dotcom_web/router_test.exs | 5 ---- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/test/dotcom_web/live/trip_planner_test.exs b/test/dotcom_web/live/trip_planner_test.exs index dedbc30e6f..f0617ef1d2 100644 --- a/test/dotcom_web/live/trip_planner_test.exs +++ b/test/dotcom_web/live/trip_planner_test.exs @@ -62,23 +62,11 @@ defmodule DotcomWeb.Live.TripPlannerTest do end) end - test "Preview version behind basic auth", %{conn: conn} do - conn = get(conn, ~p"/preview/trip-planner") - - {_header_name, header_value} = List.keyfind(conn.resp_headers, "www-authenticate", 0) - assert conn.status == 401 - assert header_value =~ "Basic" - end - describe "Trip Planner" do setup %{conn: conn} do - [username: username, password: password] = - Application.get_env(:dotcom, DotcomWeb.Router)[:basic_auth_readonly] - {:ok, view, html} = conn - |> put_req_header("authorization", "Basic " <> Base.encode64("#{username}:#{password}")) - |> live(~p"/preview/trip-planner") + |> live(~p"/trip-planner") %{html: html, view: view} end @@ -154,7 +142,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do stub_otp_results([]) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") assert render_async(view) =~ "No trips found" end @@ -190,7 +178,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do test "starts out with no 'View All Options' button", %{conn: conn, params: params} do stub_populated_otp_results() - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") refute render_async(view) =~ "View All Options" end @@ -198,7 +186,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do test "clicking 'Details' button opens details view", %{conn: conn, params: params} do stub_populated_otp_results() - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") render_async(view) view |> element("button[phx-value-index=\"0\"]", "Details") |> render_click() @@ -212,7 +200,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do } do stub_populated_otp_results() - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") render_async(view) @@ -244,7 +232,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do } end) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") render_async(view) @@ -278,7 +266,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do } end) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") render_async(view) @@ -309,7 +297,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do } end) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") render_async(view) @@ -328,7 +316,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do } do stub_otp_results([]) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") assert render_async(view) =~ "No trips found." end @@ -340,7 +328,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do {:error, [%OpenTripPlannerClient.Error{message: error_message}]} end) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") assert render_async(view) =~ error_message end @@ -353,7 +341,7 @@ defmodule DotcomWeb.Live.TripPlannerTest do {:error, [%OpenTripPlannerClient.Error{message: Faker.Lorem.sentence()}]} end) - {:ok, view, _html} = live(conn, ~p"/preview/trip-planner?#{params}") + {:ok, view, _html} = live(conn, ~p"/trip-planner?#{params}") refute render_async(view) =~ "No trips found." end diff --git a/test/dotcom_web/router_test.exs b/test/dotcom_web/router_test.exs index 9fdb9bd782..2caf6891d4 100644 --- a/test/dotcom_web/router_test.exs +++ b/test/dotcom_web/router_test.exs @@ -114,11 +114,6 @@ defmodule Phoenix.Router.RoutingTest do assert redirected_to(conn, 301) == "/betterbus-440s" end - test "trip planner with 'to' but without an address", %{conn: conn} do - conn = get(conn, "/trip-planner/to/") - assert redirected_to(conn, 301) == "/trip-planner" - end - test "redirect to canonical host securely", %{conn: conn} do System.put_env("HOST", @canonical_host) From 8292a9e313e54fbaddc7e563ead084752b3941d1 Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Mon, 6 Jan 2025 11:28:27 -0600 Subject: [PATCH 5/7] remove the smoke test --- cypress/e2e/smoke.cy.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/cypress/e2e/smoke.cy.js b/cypress/e2e/smoke.cy.js index 7416723d32..3de6db722a 100644 --- a/cypress/e2e/smoke.cy.js +++ b/cypress/e2e/smoke.cy.js @@ -152,30 +152,6 @@ describe("passes smoke test", () => { } }); - it("trip planner", () => { - cy.visit("/trip-planner"); - - // reverses the inputs - cy.get("#from").type("A"); - cy.get("#to").type("B"); - cy.get("#trip-plan-reverse-control").click(); - cy.get("#from").should("have.value", "B"); - cy.get("#to").should("have.value", "A"); - - // opens the date picker - cy.contains("#trip-plan-datepicker").should("not.exist"); - cy.get('label[for="arrive"]').click(); - cy.get("#trip-plan-datepicker"); - - // shortcut /from/ - marker A prepopulated - cy.visit("/trip-planner/from/North+Station"); - cy.get('img.leaflet-marker-icon[src="/icon-svg/icon-map-pin-a.svg"]'); - - // shortcut /to/ - marker B prepopulated - cy.visit("/trip-planner/to/North+Station"); - cy.get('img.leaflet-marker-icon[src="/icon-svg/icon-map-pin-b.svg"]'); - }); - it("alerts page", () => { cy.visit("/alerts"); cy.contains(".m-alerts__mode-buttons a", "Bus").click(); From 65dc774562d8411b4121f91a6c3c23609fda3fa3 Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Tue, 7 Jan 2025 10:13:49 -0600 Subject: [PATCH 6/7] add banner --- lib/dotcom_web/templates/layout/root.html.eex | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/dotcom_web/templates/layout/root.html.eex b/lib/dotcom_web/templates/layout/root.html.eex index cbd1103ce8..9ca7aead3a 100644 --- a/lib/dotcom_web/templates/layout/root.html.eex +++ b/lib/dotcom_web/templates/layout/root.html.eex @@ -75,6 +75,17 @@ <% end %> + <%= if assigns[:search_header?] do %> <%= render "_searchbar.html", assigns %> <% end %> From 31f634097df6c4e6dc50c130405af0ed6f6cee34 Mon Sep 17 00:00:00 2001 From: Anthony Shull Date: Tue, 7 Jan 2025 10:17:39 -0600 Subject: [PATCH 7/7] remove preview from admin page --- lib/dotcom_web/live/admin.ex | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/dotcom_web/live/admin.ex b/lib/dotcom_web/live/admin.ex index 8ae633fe2a..4202009b75 100644 --- a/lib/dotcom_web/live/admin.ex +++ b/lib/dotcom_web/live/admin.ex @@ -11,11 +11,6 @@ defmodule DotcomWeb.Live.Admin do url: Helpers.live_path(socket, DotcomWeb.Live.Admin.TripPlanFeedback), title: "Trip Planner Feedback", description: "Find and download the latest comments and votes." - }, - %{ - url: Helpers.live_path(socket, DotcomWeb.Live.TripPlanner), - title: "Trip Planner Preview", - description: "WIP on the trip planner rewrite." } ] )}