diff --git a/lib/dotcom_web/components/trip_planner/itinerary_group.ex b/lib/dotcom_web/components/trip_planner/itinerary_group.ex index e1dd1c2d01..afe02d802d 100644 --- a/lib/dotcom_web/components/trip_planner/itinerary_group.ex +++ b/lib/dotcom_web/components/trip_planner/itinerary_group.ex @@ -15,13 +15,14 @@ defmodule DotcomWeb.Components.TripPlanner.ItineraryGroup do def itinerary_group(assigns) do ~H"""
+ <% [first | rest] = @group %>
Group with <%= Enum.count(@group) %> options
- <.accordion :for={{variation, index} <- Enum.with_index(@group)} open={index === 0}> + <.accordion> <:heading> - <%= format_datetime(variation.departure) %> — <%= format_datetime(variation.arrival) %> + <%= format_datetime_full(first.departure) %> — <%= format_datetime_full(first.arrival) %> <:content> -
+
<.leg start_time={leg.start} end_time={leg.stop} @@ -32,13 +33,21 @@ defmodule DotcomWeb.Components.TripPlanner.ItineraryGroup do realtime_state={leg.realtime_state} />
+ <%= if Enum.count(rest) > 0, do: "Similar trips depart at:" %> + + <%= format_datetime_short(alternative.departure) %> +
""" end - defp format_datetime(datetime) do + defp format_datetime_full(datetime) do Timex.format!(datetime, "%-I:%M %p", :strftime) end + + defp format_datetime_short(datetime) do + Timex.format!(datetime, "%-I:%M", :strftime) + end end diff --git a/test/dotcom/trip_plan/itinerary_group_test.exs b/test/dotcom/trip_plan/itinerary_group_test.exs new file mode 100644 index 0000000000..34e362f3c9 --- /dev/null +++ b/test/dotcom/trip_plan/itinerary_group_test.exs @@ -0,0 +1,104 @@ +defmodule Dotcom.TripPlan.ItineraryTest do + @moduledoc false + + use ExUnit.Case, async: true + + import Mox + + alias Dotcom.TripPlan.ItineraryGroups + alias Test.Support.Factories.{Stops.Stop, TripPlanner.TripPlanner} + + setup do + stub(Stops.Repo.Mock, :get, fn _ -> + Stop.build(:stop) + end) + + stops = TripPlanner.build_list(3, :stop_named_position) + + {:ok, stops: stops} + end + + describe "from_itineraries/1" do + test "groups itineraries with the same mode, from, and to", %{stops: [a, b, c]} do + # SETUP + bus_a_b_leg = TripPlanner.build(:bus_leg, from: a, to: b) + subway_b_c_leg = TripPlanner.build(:subway_leg, from: b, to: c) + + itineraries = + TripPlanner.build_list(:rand.uniform(5), :itinerary, legs: [bus_a_b_leg, subway_b_c_leg]) + + # EXERCISE + grouped_itineraries = ItineraryGroups.from_itineraries(itineraries) + + # VERIFY + assert Kernel.length(grouped_itineraries) == 1 + end + + test "does not group itineraries with different modes", %{stops: [a, b, c]} do + # SETUP + bus_a_b_leg = TripPlanner.build(:bus_leg, from: a, to: b) + bus_b_c_leg = TripPlanner.build(:bus_leg, from: b, to: c) + subway_b_c_leg = TripPlanner.build(:subway_leg, from: b, to: c) + + first_itinerary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, bus_b_c_leg]) + second_interary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, subway_b_c_leg]) + + # EXERCISE + grouped_itineraries = ItineraryGroups.from_itineraries([first_itinerary, second_interary]) + + # VERIFY + assert Kernel.length(grouped_itineraries) == 2 + end + + test "does not group itineraries with different froms", %{stops: [a, b, c]} do + # SETUP + bus_a_b_leg = TripPlanner.build(:bus_leg, from: a, to: b) + bus_b_c_leg = TripPlanner.build(:bus_leg, from: b, to: c) + bus_c_a_leg = TripPlanner.build(:bus_leg, from: c, to: a) + + first_itinerary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, bus_b_c_leg]) + second_interary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, bus_c_a_leg]) + + # EXERCISE + grouped_itineraries = ItineraryGroups.from_itineraries([first_itinerary, second_interary]) + + # VERIFY + assert Kernel.length(grouped_itineraries) == 2 + end + + test "does not group itineraries with different tos", %{stops: [a, b, c]} do + # SETUP + bus_a_b_leg = TripPlanner.build(:bus_leg, from: a, to: b) + bus_b_c_leg = TripPlanner.build(:bus_leg, from: b, to: c) + bus_b_a_leg = TripPlanner.build(:bus_leg, from: b, to: a) + + first_itinerary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, bus_b_c_leg]) + second_interary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, bus_b_a_leg]) + + # EXERCISE + grouped_itineraries = ItineraryGroups.from_itineraries([first_itinerary, second_interary]) + + # VERIFY + assert Kernel.length(grouped_itineraries) == 2 + end + end + + test "ignores short walking distances of < 0.2 miles", %{stops: [a, b, c]} do + # SETUP + bus_a_b_leg = TripPlanner.build(:bus_leg, from: a, to: b) + walk_b_c_leg = TripPlanner.build(:walking_leg, from: b, to: c) |> Map.put(:distance, 0.199) + walk_c_b_leg = TripPlanner.build(:walking_leg, from: c, to: b) |> Map.put(:distance, 0.199) + bus_b_a_leg = TripPlanner.build(:bus_leg, from: b, to: a) + + first_itinerary = + TripPlanner.build(:itinerary, legs: [bus_a_b_leg, walk_b_c_leg, walk_c_b_leg, bus_b_a_leg]) + + second_itinerary = TripPlanner.build(:itinerary, legs: [bus_a_b_leg, bus_b_a_leg]) + + # EXERCISE + grouped_itineraries = ItineraryGroups.from_itineraries([first_itinerary, second_itinerary]) + + # VERIFY + assert Kernel.length(grouped_itineraries) == 1 + end +end