Skip to content

Commit

Permalink
refactor: Convert itinerary legs to segments for easier rendering (#2262
Browse files Browse the repository at this point in the history
)
  • Loading branch information
joshlarson authored Dec 11, 2024
1 parent f244770 commit de2d3dc
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 18 deletions.
42 changes: 42 additions & 0 deletions lib/dotcom/trip_plan/leg_to_segment_helper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
defmodule Dotcom.TripPlan.LegToSegmentHelper do
@moduledoc """
A simple algorithm to convert legs as returned by Open Trip Planner
into segments to be displayed by our trip planner tool.
"""

alias Dotcom.TripPlan.{PersonalDetail, TransitDetail}

def legs_to_segments(legs) do
legs
|> raw_convert_to_segments()
|> prepend_start_location()
|> append_end_location()
end

defp raw_convert_to_segments(legs) do
Enum.map(legs, &to_segment/1)
end

defp to_segment(%{mode: %PersonalDetail{}} = leg) do
{:walking_segment, leg}
end

defp to_segment(%{mode: %TransitDetail{}} = leg) do
{:transit_segment, leg}
end

defp prepend_start_location([{_, leg} | _] = segments) do
[
{:location_segment, %{time: leg.start, place: leg.from}}
| segments
]
end

defp append_end_location([{_, leg} = last_segment]) do
[last_segment, {:location_segment, %{time: leg.stop, place: leg.to}}]
end

defp append_end_location([first_segment | rest_of_segments]) do
[first_segment | append_end_location(rest_of_segments)]
end
end
52 changes: 35 additions & 17 deletions lib/dotcom_web/components/trip_planner/itinerary_detail.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule DotcomWeb.Components.TripPlanner.ItineraryDetail do
import DotcomWeb.Components.TripPlanner.TransitLeg, only: [transit_leg: 1]
import DotcomWeb.Components.TripPlanner.WalkingLeg, only: [walking_leg: 1]

alias Dotcom.TripPlan.{PersonalDetail, TransitDetail}
alias Dotcom.TripPlan.LegToSegmentHelper

def itinerary_detail(
%{
Expand Down Expand Up @@ -77,27 +77,45 @@ defmodule DotcomWeb.Components.TripPlanner.ItineraryDetail do

defp specific_itinerary_detail(assigns) do
assigns =
assigns
|> assign(:start_place, List.first(assigns.itinerary.legs).from)
|> assign(:start_time, List.first(assigns.itinerary.legs).start)
|> assign(:end_place, List.last(assigns.itinerary.legs).to)
|> assign(:end_time, List.last(assigns.itinerary.legs).stop)
assign(
assigns,
:segments,
LegToSegmentHelper.legs_to_segments(assigns.itinerary.legs)
)

~H"""
<div class="mt-4">
<.place place={@start_place} time={@start_time} />
<div
:for={leg <- @itinerary.legs}
class={"#{if(match?(%TransitDetail{}, leg.mode), do: "bg-gray-bordered-background")}"}
>
<%= if match?(%PersonalDetail{}, leg.mode) do %>
<.walking_leg leg={leg} />
<% else %>
<.transit_leg leg={leg} />
<% end %>
<div :for={segment <- @segments}>
<.segment segment={segment} />
</div>
<.place place={@end_place} time={@end_time} />
</div>
"""
end

defp segment(%{segment: {:location_segment, %{time: time, place: place}}} = assigns) do
assigns =
assigns
|> assign(:time, time)
|> assign(:place, place)

~H"""
<.place place={@place} time={@time} />
"""
end

defp segment(%{segment: {:walking_segment, leg}} = assigns) do
assigns = assign(assigns, :leg, leg)

~H"""
<.walking_leg leg={@leg} />
"""
end

defp segment(%{segment: {:transit_segment, leg}} = assigns) do
assigns = assign(assigns, :leg, leg)

~H"""
<.transit_leg leg={@leg} />
"""
end
end
2 changes: 1 addition & 1 deletion lib/dotcom_web/components/trip_planner/transit_leg.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule DotcomWeb.Components.TripPlanner.TransitLeg do

def transit_leg(assigns) do
~H"""
<div>
<div class="bg-gray-bordered-background">
<.place
place={@leg.from}
time={@leg.start}
Expand Down
23 changes: 23 additions & 0 deletions test/dotcom/trip_plan/leg_to_segment_helper_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Dotcom.TripPlan.LegToSegmentHelperTest do
@moduledoc false

use ExUnit.Case, async: true

alias Dotcom.TripPlan.LegToSegmentHelper
alias Dotcom.TripPlan.{Leg, PersonalDetail, TransitDetail}

test "works for a typical walking-transit-walking itinerary and puts a location on either end" do
assert [
{:location_segment, _},
{:walking_segment, _},
{:transit_segment, _},
{:walking_segment, _},
{:location_segment, _}
] =
LegToSegmentHelper.legs_to_segments([
%Leg{mode: %PersonalDetail{}},
%Leg{mode: %TransitDetail{}},
%Leg{mode: %PersonalDetail{}}
])
end
end

0 comments on commit de2d3dc

Please sign in to comment.