diff --git a/lib/arrow/shuttles.ex b/lib/arrow/shuttles.ex
index bcbd4704..123c8efe 100644
--- a/lib/arrow/shuttles.ex
+++ b/lib/arrow/shuttles.ex
@@ -48,6 +48,14 @@ defmodule Arrow.Shuttles do
"""
def get_shape!(id), do: Repo.get!(Shape, id)
+ @doc """
+ Gets the shapes specifiied by a list of ids. Does not raise if any of the ids are missing,
+ meaning the resulting list may be shorter than the input list.
+ """
+ def get_shapes(ids) do
+ Repo.all(from s in Shape, where: s.id in ^ids)
+ end
+
@doc """
Gets a shapes upload struct associated with a given shape.
diff --git a/lib/arrow_web/live/shuttle_live/shuttle_live.ex b/lib/arrow_web/live/shuttle_live/shuttle_live.ex
index 8d5b36c8..a971852e 100644
--- a/lib/arrow_web/live/shuttle_live/shuttle_live.ex
+++ b/lib/arrow_web/live/shuttle_live/shuttle_live.ex
@@ -3,6 +3,7 @@ defmodule ArrowWeb.ShuttleViewLive do
import Phoenix.HTML.Form
alias Arrow.Shuttles
alias Arrow.Shuttles.Shuttle
+ alias ArrowWeb.ShapeView
embed_templates "shuttle_live/*"
@@ -14,6 +15,7 @@ defmodule ArrowWeb.ShuttleViewLive do
attr :http_action, :string
attr :gtfs_disruptable_routes, :list, required: true
attr :shapes, :list, required: true
+ attr :map_props, :map, required: false, default: %{}
def shuttle_form(assigns) do
~H"""
@@ -60,6 +62,7 @@ defmodule ArrowWeb.ShuttleViewLive do
/>
+ <%= live_react_component("Components.ShapeViewMap", @map_props, id: "shuttle-view-map") %>
define route
<.inputs_for :let={f_route} field={f[:routes]}>
@@ -152,6 +155,14 @@ defmodule ArrowWeb.ShuttleViewLive do
"""
end
+ defp shapes_to_shapeviews(shapes) do
+ shapes
+ |> Enum.map(&Shuttles.get_shapes_upload/1)
+ |> Enum.reject(&(&1 == {:ok, :disabled}))
+ |> Enum.map(&ShapeView.shapes_map_view/1)
+ |> Enum.map(&List.first(&1.shapes))
+ end
+
def mount(%{"id" => id} = _params, session, socket) do
logout_url = session["logout_url"]
shuttle = Shuttles.get_shuttle!(id)
@@ -160,6 +171,14 @@ defmodule ArrowWeb.ShuttleViewLive do
shapes = Shuttles.list_shapes()
form = to_form(changeset)
+ shuttle_shapes =
+ shuttle
+ |> Map.get(:routes)
+ |> Enum.map(&Map.get(&1, :shape))
+ |> Enum.reject(&is_nil/1)
+
+ shapes_map_view = shapes_to_shapeviews(shuttle_shapes)
+
socket =
socket
|> assign(:form, form)
@@ -170,6 +189,7 @@ defmodule ArrowWeb.ShuttleViewLive do
|> assign(:gtfs_disruptable_routes, gtfs_disruptable_routes)
|> assign(:shapes, shapes)
|> assign(:logout_url, logout_url)
+ |> assign(:map_props, %{shapes: shapes_map_view})
{:ok, socket}
end
@@ -196,19 +216,31 @@ defmodule ArrowWeb.ShuttleViewLive do
|> assign(:gtfs_disruptable_routes, gtfs_disruptable_routes)
|> assign(:shapes, shapes)
|> assign(:logout_url, logout_url)
+ |> assign(:map_props, %{shapes: []})
{:ok, socket}
end
- def handle_event("validate", params, socket) do
- shuttle_params = params |> combine_params()
-
- form =
- socket.assigns.shuttle
- |> Shuttles.change_shuttle(shuttle_params)
- |> to_form(action: :validate)
+ # A new shape is selected
+ def handle_event(
+ "validate",
+ %{"_target" => ["shuttle", "routes", _direction_id, "shape_id"]} = params,
+ socket
+ ) do
+ shapes =
+ [
+ params["shuttle"]["routes"]["0"]["shape_id"],
+ params["shuttle"]["routes"]["1"]["shape_id"]
+ ]
+ |> Enum.reject(&(&1 == ""))
+ |> Shuttles.get_shapes()
+ |> shapes_to_shapeviews()
+
+ validate(params, assign(socket, :map_props, %{socket.assigns.map_props | shapes: shapes}))
+ end
- {:noreply, assign(socket, form: form)}
+ def handle_event("validate", params, socket) do
+ validate(params, socket)
end
def handle_event("edit", params, socket) do
@@ -306,4 +338,15 @@ defmodule ArrowWeb.ShuttleViewLive do
route_changeset
end
end
+
+ defp validate(params, socket) do
+ shuttle_params = params |> combine_params()
+
+ form =
+ socket.assigns.shuttle
+ |> Shuttles.change_shuttle(shuttle_params)
+ |> to_form(action: :validate)
+
+ {:noreply, assign(socket, form: form)}
+ end
end
diff --git a/lib/arrow_web/live/shuttle_live/shuttle_view_live.html.heex b/lib/arrow_web/live/shuttle_live/shuttle_view_live.html.heex
index 9648e3a5..21b34d37 100644
--- a/lib/arrow_web/live/shuttle_live/shuttle_view_live.html.heex
+++ b/lib/arrow_web/live/shuttle_live/shuttle_view_live.html.heex
@@ -8,6 +8,7 @@
http_action={@http_action}
gtfs_disruptable_routes={@gtfs_disruptable_routes}
shapes={@shapes}
+ map_props={@map_props}
/>
<.back navigate={~p"/shuttles"}>Back to shuttles
diff --git a/test/arrow/shuttles_test.exs b/test/arrow/shuttles_test.exs
index 3afef71f..abb7de20 100644
--- a/test/arrow/shuttles_test.exs
+++ b/test/arrow/shuttles_test.exs
@@ -24,7 +24,7 @@ defmodule Arrow.ShuttlesTest do
end
test "create_shape/1 with name that does not end in -S adds it" do
- Application.put_env(:arrow, :shape_storage_enabled?, true)
+ reassign_env(:shape_storage_enabled?, true)
Application.put_env(:arrow, :shape_storage_prefix, "prefix/#{Ecto.UUID.generate()}/")
assert {:ok, %Shape{} = shape} =
@@ -64,6 +64,17 @@ defmodule Arrow.ShuttlesTest do
assert Shuttles.get_shape!(shape.id) == shape
end
+ test "get_shapes returns all shapes with matching ids" do
+ shapes = [shape_fixture(), shape_fixture()]
+ shape_ids = Enum.map(shapes, fn shape -> shape.id end)
+ assert MapSet.new(Shuttles.get_shapes(shape_ids)) == MapSet.new(shapes)
+ end
+
+ test "get_shapes returns empty list when no shapes match" do
+ shape_ids = [1, 2, 3]
+ assert [] == Shuttles.get_shapes(shape_ids)
+ end
+
test "create_shapes/1 with valid data creates a shape" do
assert {:ok, [{:ok, %Shape{} = shape}]} = Shuttles.create_shapes([@valid_attrs])
assert shape.name == "some name-S"