Skip to content

Commit

Permalink
Take trip planner query params into account in the new trip planner (#…
Browse files Browse the repository at this point in the history
…2218)

* run query params through an anti corruption layer

* dont account for time selections

* add handle change back in

* docs

* mix format

* function doc

* format

* alias

* submit the form if form values are present

* rename function and add tests

* rearrange assert

* test a given false mode
  • Loading branch information
anthonyshull authored Nov 13, 2024
1 parent 24ddd2a commit ae240e0
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 28 deletions.
48 changes: 48 additions & 0 deletions lib/dotcom/trip_plan/anti_corruption_layer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Dotcom.TripPlan.AntiCorruptionLayer do
@moduledoc """
This anti-corruption layer is responsible for converting the data from the old trip planner query params to the new trip planner form values.
Currently, not all modes are sent. So, we default to setting them to 'false' if they aren't set.
Likewise with wheelchair, we default to 'false' if it isn't set because the old trip planner worked by just not setting it rather than setting it to 'false'.
We ignore datetime_type and datetime and allow those to be set to 'now' and the current time respectively.
"""

@doc """
Given the params from the old trip planner, convert them to the new trip planner form values.
If no plan is given, then we default to empty form values.
"""
def convert_old_params(%{"plan" => params}) do
%{
"from" => %{
"latitude" => Map.get(params, "from_latitude"),
"longitude" => Map.get(params, "from_longitude"),
"name" => Map.get(params, "from"),
"stop_id" => Map.get(params, "from_stop_id", "")
},
"modes" => Map.get(params, "modes") |> convert_modes(),
"to" => %{
"latitude" => Map.get(params, "to_latitude"),
"longitude" => Map.get(params, "to_longitude"),
"name" => Map.get(params, "to"),
"stop_id" => Map.get(params, "to_stop_id", "")
},
"wheelchair" => Map.get(params, "wheelchair") || "false"
}
end

def convert_old_params(_), do: convert_old_params(%{"plan" => %{}})

defp convert_modes(modes) when is_map(modes) do
default_modes =
for {k, _} <- Dotcom.TripPlan.InputForm.initial_modes(), into: %{}, do: {k, "false"}

modes
|> Enum.reduce(default_modes, fn {key, value}, acc ->
Map.put(acc, String.upcase(key), value)
end)
end

defp convert_modes(_), do: Dotcom.TripPlan.InputForm.initial_modes()
end
76 changes: 53 additions & 23 deletions lib/dotcom_web/components/live_components/trip_planner_form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,34 @@ defmodule DotcomWeb.Components.LiveComponents.TripPlannerForm do

@impl true
def mount(socket) do
form_defaults = %{
"datetime_type" => "now",
"datetime" => Timex.now("America/New_York"),
"modes" => InputForm.initial_modes(),
"wheelchair" => true
}
{:ok, socket}
end

@impl true
@doc """
If form values are passed in, we merge them with the defaults and submit the form.
Otherwise, we just render the form.
"""
def update(assigns, socket) do
form_defaults = get_form_defaults(assigns)

defaults = %{
form: %InputForm{} |> InputForm.changeset(form_defaults) |> to_form(),
location_keys: InputForm.Location.fields(),
show_datepicker: false
}

{:ok, assign(socket, defaults)}
new_socket =
socket
|> assign(assigns)
|> assign(defaults)

if assigns[:form_values] do
save_form(form_defaults, new_socket)
end

{:ok, new_socket}
end

@impl true
Expand Down Expand Up @@ -177,22 +191,7 @@ defmodule DotcomWeb.Components.LiveComponents.TripPlannerForm do
end

def handle_event("save_form", %{"input_form" => params}, socket) do
params
|> InputForm.validate_params()
|> Ecto.Changeset.apply_action(:update)
|> case do
{:ok, data} ->
send(self(), {:updated_form, data})

{:noreply, socket}

{:error, changeset} ->
form =
changeset
|> Phoenix.Component.to_form()

{:noreply, assign(socket, %{form: form})}
end
{:noreply, save_form(params, socket)}
end

defp datepicker_config do
Expand All @@ -204,6 +203,18 @@ defmodule DotcomWeb.Components.LiveComponents.TripPlannerForm do
}
end

defp get_form_defaults(assigns) do
assigns
|> Map.get(:form_values, %{
"modes" => InputForm.initial_modes(),
"wheelchair" => true
})
|> Map.merge(%{
"datetime_type" => "now",
"datetime" => Timex.now("America/New_York")
})
end

defp nearest_5_minutes do
datetime = Timex.now("America/New_York")
minutes = datetime.minute
Expand All @@ -212,4 +223,23 @@ defmodule DotcomWeb.Components.LiveComponents.TripPlannerForm do

Timex.shift(datetime, minutes: added_minutes)
end

defp save_form(params, socket) do
params
|> InputForm.validate_params()
|> Ecto.Changeset.apply_action(:update)
|> case do
{:ok, data} ->
send(self(), {:updated_form, data})

socket

{:error, changeset} ->
form =
changeset
|> Phoenix.Component.to_form()

assign(socket, %{form: form})
end
end
end
16 changes: 11 additions & 5 deletions lib/dotcom_web/live/trip_planner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ defmodule DotcomWeb.Live.TripPlanner do

use DotcomWeb, :live_view

alias DotcomWeb.Components.LiveComponents.TripPlannerForm
alias Dotcom.TripPlan.{InputForm.Modes, ItineraryGroups}

import DotcomWeb.Components.TripPlanner.ItineraryGroup, only: [itinerary_group: 1]
import MbtaMetro.Components.{Feedback, Spinner}

alias DotcomWeb.Components.LiveComponents.TripPlannerForm
alias Dotcom.TripPlan.{AntiCorruptionLayer, InputForm.Modes, ItineraryGroups}

@form_id "trip-planner-form"

@map_config Application.compile_env!(:mbta_metro, :map)

@impl true
def mount(_params, _session, socket) do
def mount(params, _session, socket) do
socket =
socket
|> assign(:error, nil)
|> assign(:form_name, @form_id)
|> assign(:form_values, AntiCorruptionLayer.convert_old_params(params))
|> assign(:map_config, @map_config)
|> assign(:from, [])
|> assign(:to, [])
Expand All @@ -39,7 +40,12 @@ defmodule DotcomWeb.Live.TripPlanner do
~H"""
<h1>Trip Planner <mark style="font-weight: 400">Preview</mark></h1>
<div style="row">
<.live_component module={TripPlannerForm} id={@form_name} form_name={@form_name} />
<.live_component
module={TripPlannerForm}
id={@form_name}
form_name={@form_name}
form_values={@form_values}
/>
<section :if={@submitted_values} class="mt-2 mb-6">
<p class="text-lg font-semibold mb-0"><%= submission_summary(@submitted_values) %></p>
<p><%= time_summary(@submitted_values) %></p>
Expand Down
50 changes: 50 additions & 0 deletions test/dotcom/trip_plan/anti_corruption_layer_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
defmodule Dotcom.TripPlan.AntiCorruptionLayerTest do
use ExUnit.Case

import Dotcom.TripPlan.AntiCorruptionLayer, only: [convert_old_params: 1]

describe "convert_old_params/1" do
test "returns all defaults when no params are given" do
assert convert_old_params(%{}) == convert_old_params(%{"plan" => %{}})
end

test "sets all modes to true when no modes are given" do
old_params = %{
"plan" => %{}
}

new_params = convert_old_params(old_params)

assert new_params["modes"] == Dotcom.TripPlan.InputForm.initial_modes()
end

test "sets given modes as given and all non-given as false" do
old_params = %{
"plan" => %{
"modes" => %{
"bus" => "true",
"ferry" => "false",
"subway" => "true"
}
}
}

new_params = convert_old_params(old_params)

assert new_params["modes"]["BUS"] == "true"
assert new_params["modes"]["FERRY"] == "false"
assert new_params["modes"]["RAIL"] == "false"
assert new_params["modes"]["SUBWAY"] == "true"
end

test "defaults to wheelchair false when no wheelchair is given" do
old_params = %{
"plan" => %{}
}

new_params = convert_old_params(old_params)

assert new_params["wheelchair"] == "false"
end
end
end

0 comments on commit ae240e0

Please sign in to comment.