Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bae3429
Added vechicle_id to vehicle info of trip details in perdicted schedu…
lvachon1 Mar 3, 2026
d0bcd07
Code cleanup
lvachon1 Mar 3, 2026
49d5d84
Added vehicle id to vehicle info in trip details
lvachon1 Mar 4, 2026
8b75380
Type fixing
lvachon1 Mar 4, 2026
766d94a
Code cleanup
lvachon1 Mar 4, 2026
e538420
Cleaned up boat_name code
lvachon1 Mar 4, 2026
aa56cd7
Turns out the react pattern of returning a list of strings to render …
lvachon1 Mar 4, 2026
13756e8
Removed unused upcoming deartures check
lvachon1 Mar 4, 2026
c87140f
Renamed track_info section to additional_info
lvachon1 Mar 4, 2026
4b7cc28
It looks like early return isn't a thing in elixir
lvachon1 Mar 4, 2026
b298b08
Moved boat name logic to trip_details, changed field from vehicle_id …
lvachon1 Mar 4, 2026
71ef594
Merge branch 'main' into lev/feat/sf/live_ferry_data
lvachon1 Mar 4, 2026
3c98edb
Fixed updated logic to only show the name of ferries
lvachon1 Mar 4, 2026
6d149f3
Updated logic to detect the trip mode
lvachon1 Mar 4, 2026
35bc25d
Found a cleaner way to get the mode
lvachon1 Mar 4, 2026
bb4b8de
Lint
lvachon1 Mar 4, 2026
ea65676
Added extra nil guard for vehicles with a nil route_id
lvachon1 Mar 4, 2026
b0b7c2f
Style guides recommend italics for ship names
lvachon1 Mar 4, 2026
6f95b77
Moved vehilce name code to separation function. Added test coverage,…
lvachon1 Mar 5, 2026
4597468
Merge branch 'main' into lev/feat/sf/live_ferry_data
lvachon1 Mar 5, 2026
aac9c44
Merge branch 'main' into lev/feat/sf/live_ferry_data
lvachon1 Mar 5, 2026
d7c14c4
Update test/dotcom/schedule_finder/trip_details_test.exs
lvachon1 Mar 6, 2026
73a9aaf
Update lib/dotcom/schedule_finder/trip_details.ex
lvachon1 Mar 6, 2026
546f98e
Update lib/dotcom/schedule_finder/trip_details.ex
lvachon1 Mar 6, 2026
cf51778
Code cleanup
lvachon1 Mar 6, 2026
d4605d4
Added ferry factory to test support
lvachon1 Mar 6, 2026
0877cbe
Added ferry check when renderin vehicle names in italic
lvachon1 Mar 6, 2026
222a8ff
My setup has been broken somehow, so I have to manually lint and format
lvachon1 Mar 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions lib/dotcom/schedule_finder/trip_details.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ defmodule Dotcom.ScheduleFinder.TripDetails do
:status,
:stop_id,
:stop_name,
:stop_sequence
:stop_sequence,
:vehicle_name
]

@type trip_vehicle_status_t() ::
Expand All @@ -67,7 +68,8 @@ defmodule Dotcom.ScheduleFinder.TripDetails do
status: trip_vehicle_status_t(),
stop_id: Stops.Stop.id_t(),
stop_name: String.t(),
stop_sequence: non_neg_integer()
stop_sequence: non_neg_integer(),
vehicle_name: nil | String.t()
}
end

Expand All @@ -77,14 +79,15 @@ defmodule Dotcom.ScheduleFinder.TripDetails do
alias Schedules.{Schedule, Trip}
alias Vehicles.Vehicle

@routes_repo Application.compile_env!(:dotcom, :repo_modules)[:routes]
@stops_repo Application.compile_env!(:dotcom, :repo_modules)[:stops]

@spec trip_details(%{
predicted_schedules: [PredictedSchedule.t()],
trip_vehicle: Vehicles.Vehicle.t() | nil
}) :: __MODULE__.t()
def trip_details(%{predicted_schedules: predicted_schedules, trip_vehicle: vehicle}) do
vehicle_info = vehicle_info(vehicle, predicted_schedules)
vehicle_info = vehicle_info(vehicle, predicted_schedules) |> add_vehicle_name(vehicle)
Comment thread
lvachon1 marked this conversation as resolved.

stops =
predicted_schedules
Expand All @@ -110,6 +113,28 @@ defmodule Dotcom.ScheduleFinder.TripDetails do
}
end

defp add_vehicle_name(vehicle_info, nil), do: vehicle_info

defp add_vehicle_name(vehicle_info, vehicle) do
Comment thread
lvachon1 marked this conversation as resolved.
vehicle_id = Map.get(vehicle, :id, nil)

mode =
if is_nil(vehicle.route_id) do
nil
else
vehicle.route_id |> @routes_repo.get() |> Route.type_atom()
end

# Only add vehicle names for ferries (for now?) Turns out busses have vehicle IDs too.
# While it is cool to see that "The Y1795" is approaching, I'm not sure that's what we want
if mode == :ferry do
vehicle_info
|> Map.put(:vehicle_name, boat_name(vehicle_id))
else
vehicle_info
end
end

defp trip_stop_time(predicted_schedule) do
%Route{type: route_type} = PredictedSchedule.route(predicted_schedule)
status = PredictedSchedule.status(predicted_schedule)
Expand Down Expand Up @@ -238,4 +263,17 @@ defmodule Dotcom.ScheduleFinder.TripDetails do
defp vehicle_at_stop?(stop, vehicle) do
stop.stop_id == vehicle.stop_id && stop.stop_sequence == vehicle.stop_sequence
end

defp boat_name(nil = _name) do
nil
end

defp boat_name(name) do
("The " <> name)
|> String.split(" ")
|> Enum.map_join(
" ",
&String.capitalize/1
)
end
end
26 changes: 15 additions & 11 deletions lib/dotcom_web/live/schedule_finder_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ defmodule DotcomWeb.ScheduleFinderLive do
<.stop_banner stop={@stop} />
<div class="px-3 py-xl flex flex-col gap-y-xl">
<.alert_banner alerts={@alerts} />
<section :if={show_upcoming_departures?(@route)}>
<section>
<h2 class="mt-0 mb-md">{~t"Upcoming Departures"}</h2>
<%= if ServicePatterns.has_service?(route: @route.id) do %>
<.upcoming_departures_section
Expand Down Expand Up @@ -500,7 +500,7 @@ defmodule DotcomWeb.ScheduleFinderLive do
attr :route, Route, required: true

slot :headsign, required: true
slot :track_info
slot :additional_info
slot :time, required: true

defp departure_heading(assigns) do
Expand All @@ -513,13 +513,13 @@ defmodule DotcomWeb.ScheduleFinderLive do
<span>{render_slot(@headsign)}</span>
</div>

<div :if={@track_info} class="flex items-center gap-2">
<div :if={@additional_info} class="flex items-center gap-2">
<div class="h-0 invisible shrink-0">
<RouteComponents.route_icon size="small" route={@route} />
</div>

<div class="leading-none text-sm">
{render_slot(@track_info)}
{render_slot(@additional_info)}
</div>
</div>
</div>
Expand Down Expand Up @@ -559,9 +559,9 @@ defmodule DotcomWeb.ScheduleFinderLive do
</div>
</:headsign>

<:track_info :if={departure.route.type == 2 && departure.trip_name}>
<:additional_info :if={departure.route.type == 2 && departure.trip_name}>
{~t(Train)} {departure.trip_name}
</:track_info>
</:additional_info>

<:time><.formatted_time time={departure.time} /></:time>
</.departure_heading>
Expand Down Expand Up @@ -764,13 +764,20 @@ defmodule DotcomWeb.ScheduleFinderLive do
<.departure_heading route={@upcoming_departure.route}>
<:headsign>{@upcoming_departure.headsign}</:headsign>

<:track_info :if={@upcoming_departure.trip_name}>
<:additional_info :if={@upcoming_departure.trip_name}>
{gettext("Train %{trip_name}", trip_name: @upcoming_departure.trip_name)}
<span aria-hidden="true">
&bull;
</span>
{@upcoming_departure.platform_name || ~t"Track TBA"}
</:track_info>
</:additional_info>

<:additional_info :if={
@upcoming_departure.trip_details.vehicle_info.vehicle_name &&
@upcoming_departure.route.type == 4
}>
<i>{@upcoming_departure.trip_details.vehicle_info.vehicle_name}</i>
Comment thread
lvachon1 marked this conversation as resolved.
</:additional_info>

<:time>
<div class="flex flex-col items-end">
Expand Down Expand Up @@ -1115,7 +1122,4 @@ defmodule DotcomWeb.ScheduleFinderLive do
</div>
"""
end

defp show_upcoming_departures?(%Route{} = route), do: Route.type_atom(route) != :ferry
defp show_upcoming_departures?(_), do: false
end
97 changes: 97 additions & 0 deletions test/dotcom/schedule_finder/trip_details_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -830,4 +830,101 @@ defmodule Dotcom.ScheduleFinder.TripDetailsTest do
current_stop.name | Enum.map(future_stops, & &1.name)
]
end

test "shows vehicle names for ferries if available" do
platform_name = Faker.Pizza.sauce()
stop = Factories.Stops.Stop.build(:stop, parent_id: nil, platform_name: platform_name)
stop_id = stop.id
trip = Factories.Schedules.Trip.build(:trip)

stub(Routes.Repo.Mock, :get, fn id ->
Factories.Routes.Route.ferry_route_factory(%{id: id})
end)

stub(Stops.Repo.Mock, :get, fn
^stop_id -> stop
_ -> Factories.Stops.Stop.build(:stop)
end)

first_predicted_schedule = %PredictedSchedule{
prediction:
Factories.Predictions.Prediction.build(:prediction,
trip: trip,
platform_stop_id: stop_id
),
schedule: Factories.Schedules.Schedule.build(:schedule, trip: trip)
}

predicted_schedules = [first_predicted_schedule]

route_id = Faker.Util.pick(["Boat-F1", "Boat-F2H"])
vehicle_id = Faker.Pokemon.name() <> " " <> Faker.Pokemon.name()

vehicle =
Factories.Vehicles.Vehicle.build(:vehicle,
stop_id: stop_id,
trip_id: trip.id,
id: vehicle_id |> String.upcase(),
route_id: route_id
)

trip_details =
TripDetails.trip_details(%{
predicted_schedules: predicted_schedules,
trip_vehicle: vehicle
})

vehicle_info = trip_details.vehicle_info
assert vehicle_info.vehicle_name == "The " <> vehicle_id
end

test "does not show vehicle names for busses and such" do
platform_name = Faker.Pizza.sauce()
stop = Factories.Stops.Stop.build(:stop, parent_id: nil, platform_name: platform_name)
stop_id = stop.id
trip = Factories.Schedules.Trip.build(:trip)

stub(Routes.Repo.Mock, :get, fn id ->
Factories.Routes.Route.build(
Faker.Util.pick([:subway_route, :bus_route, :commuter_rail_route]),
id: id
)
end)

stub(Stops.Repo.Mock, :get, fn
^stop_id -> stop
_ -> Factories.Stops.Stop.build(:stop)
end)

first_predicted_schedule = %PredictedSchedule{
prediction:
Factories.Predictions.Prediction.build(:prediction,
trip: trip,
platform_stop_id: stop_id
),
schedule: Factories.Schedules.Schedule.build(:schedule, trip: trip)
}

predicted_schedules = [first_predicted_schedule]

route_id = Faker.Util.pick(["1", "2", "Red", "Green-B"])
vehicle_id = Faker.Pokemon.name()

vehicle =
Factories.Vehicles.Vehicle.build(:vehicle,
stop_id: stop_id,
trip_id: trip.id,
id: vehicle_id
)
|> Map.put(:route_id, route_id)

trip_details =
TripDetails.trip_details(%{
predicted_schedules: predicted_schedules,
trip_vehicle: vehicle
})

vehicle_info = trip_details.vehicle_info
assert vehicle_info.vehicle_name == nil
end
end
3 changes: 3 additions & 0 deletions test/support/factories/routes/route.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ defmodule Test.Support.Factories.Routes.Route do
def commuter_rail_route_factory(attrs),
do: build(:route, attrs |> Map.put(:type, 2))

def ferry_route_factory(attrs),
do: build(:route, attrs |> Map.put(:type, 4))

def logan_express_route_factory(attrs) do
%{
description: nil,
Expand Down