-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(TripPlanner): transit leg and itinerary locations (#2251)
--------- Co-authored-by: Josh Larson <jlarson@mbta.com>
- Loading branch information
1 parent
acb1cba
commit 92cc1b3
Showing
8 changed files
with
240 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
defmodule DotcomWeb.Components.TripPlanner.Place do | ||
@moduledoc """ | ||
A component to display a specific location in the itinerary detail. | ||
""" | ||
|
||
use DotcomWeb, :component | ||
|
||
alias Routes.Route | ||
alias Stops.Stop | ||
|
||
attr :place, :map, required: true | ||
attr :time, :any, required: true | ||
attr :route, :map, default: nil | ||
|
||
def place(assigns) do | ||
stop_url = stop_url(assigns.route, assigns.place.stop) | ||
|
||
assigns = | ||
assign(assigns, %{ | ||
stop_url: stop_url, | ||
tag_name: if(stop_url, do: "a", else: "div") | ||
}) | ||
|
||
~H""" | ||
<.dynamic_tag | ||
tag_name={@tag_name} | ||
href={@stop_url} | ||
class="bg-gray-bordered-background px-3 py-2 rounded-lg grid grid-cols-[1.5rem_auto_1fr] items-center gap-2 w-full hover:no-underline text-black" | ||
> | ||
<.location_icon route={@route} class="h-6 w-6" /> | ||
<strong class="flex items-center gap-2"> | ||
{@place.name} | ||
<.icon | ||
:if={!is_nil(@place.stop) and Stop.accessible?(@place.stop)} | ||
type="icon-svg" | ||
name="icon-accessible-default" | ||
class="h-5 w-5 ml-0.5 shrink-0" | ||
aria-hidden="true" | ||
/> | ||
</strong> | ||
<time class="text-right no-wrap">{format_time(@time)}</time> | ||
</.dynamic_tag> | ||
""" | ||
end | ||
|
||
defp stop_url(%Route{external_agency_name: nil}, %Stop{} = stop) do | ||
~p"/stops/#{stop}" | ||
end | ||
|
||
defp stop_url(_, _), do: nil | ||
|
||
defp location_icon(%{route: %Route{}} = assigns) do | ||
icon_name = | ||
if(Routes.Route.type_atom(assigns.route) in [:bus, :logan_express, :massport_shuttle], | ||
do: "icon-stop-default", | ||
else: "icon-circle-t-default" | ||
) | ||
|
||
assigns = assign(assigns, :icon_name, icon_name) | ||
|
||
~H""" | ||
<.icon type="icon-svg" class={@class} name={@icon_name} /> | ||
""" | ||
end | ||
|
||
defp location_icon(assigns) do | ||
~H""" | ||
<.icon class={"#{@class} fill-brand-primary"} name="location-dot" /> | ||
""" | ||
end | ||
|
||
defp format_time(datetime), do: Timex.format!(datetime, "%-I:%M %p", :strftime) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
defmodule DotcomWeb.Components.TripPlanner.TransitLeg do | ||
@moduledoc """ | ||
A transit leg of a trip. | ||
Includes styling for the traversed route & a list of intermediate stops. | ||
""" | ||
|
||
use Phoenix.Component | ||
|
||
import DotcomWeb.Components.RouteSymbols, only: [route_symbol: 1] | ||
import DotcomWeb.Components.TripPlanner.Place | ||
import MbtaMetro.Components.Icon, only: [icon: 1] | ||
|
||
alias Dotcom.TripPlan.TransitDetail | ||
alias Routes.Route | ||
|
||
@doc """ | ||
Renders a transit leg. | ||
Must be given a `leg` | ||
""" | ||
|
||
attr :leg, :any, required: true | ||
|
||
def transit_leg(assigns) do | ||
~H""" | ||
<div> | ||
<.place | ||
place={@leg.from} | ||
time={@leg.start} | ||
route={if(match?(%TransitDetail{}, @leg.mode), do: @leg.mode.route)} | ||
/> | ||
<div class={"bg-gray-bordered-background ml-5 border-l-8 #{leg_line_class(@leg.mode.route)}"}> | ||
<%= if Enum.count(@leg.mode.intermediate_stops) < 2 do %> | ||
<.leg_summary leg={@leg} /> | ||
<.leg_details leg={@leg} /> | ||
<% else %> | ||
<details class="group"> | ||
<summary class="flex cursor-pointer list-none gap-2 relative"> | ||
<.leg_summary leg={@leg} /> | ||
<.icon | ||
name="chevron-up" | ||
class="group-open:rotate-180 w-4 h-4 absolute top-3 right-3 fill-brand-primary" | ||
/> | ||
</summary> | ||
<.leg_details leg={@leg} /> | ||
</details> | ||
<% end %> | ||
</div> | ||
<.place | ||
place={@leg.to} | ||
time={@leg.stop} | ||
route={if(match?(%TransitDetail{}, @leg.mode), do: @leg.mode.route)} | ||
/> | ||
</div> | ||
""" | ||
end | ||
|
||
defp leg_line_class(%Route{external_agency_name: "Massport"}) do | ||
"border-massport" | ||
end | ||
|
||
defp leg_line_class(%Route{external_agency_name: "Logan Express", name: name}) do | ||
"border-logan-express-#{name}" | ||
end | ||
|
||
defp leg_line_class(%Route{} = route) do | ||
route | ||
|> Routes.Route.icon_atom() | ||
|> CSSHelpers.atom_to_class() | ||
|> then(&"border-#{&1}") | ||
end | ||
|
||
defp leg_line_class(_), do: "" | ||
|
||
defp leg_summary(assigns) do | ||
assigns = assign(assigns, :stops_count, Enum.count(assigns.leg.mode.intermediate_stops) + 1) | ||
|
||
~H""" | ||
<div class="gap-x-1 py-2 grid grid-rows-2 grid-cols-[min-content_max-content] pl-4"> | ||
<.route_symbol route={@leg.mode.route} /> | ||
<span class="font-semibold">{@leg.mode.trip_id}</span> | ||
<div class="text-sm col-start-2 row-start-2"> | ||
Ride the {route_name(@leg.mode.route)} | ||
<span class="font-semibold">{@stops_count} {Inflex.inflect("stop", @stops_count)}</span> | ||
</div> | ||
</div> | ||
""" | ||
end | ||
|
||
# Returns the name of the route for the given row. | ||
# If there is an external agency name, we use the long name. | ||
# If it is a bus, we use the short name. | ||
# For all others, we use the long name. | ||
defp route_name(%Route{external_agency_name: agency, long_name: long_name}) | ||
when is_binary(agency) and is_binary(long_name), | ||
do: long_name | ||
|
||
defp route_name(%Route{name: name, type: 3}) | ||
when is_binary(name), | ||
do: "#{name} bus" | ||
|
||
defp route_name(%Route{long_name: long_name}) | ||
when is_binary(long_name), | ||
do: long_name | ||
|
||
defp route_name(%Route{name: name}), do: name | ||
defp route_name(_), do: nil | ||
|
||
defp leg_details(assigns) do | ||
~H""" | ||
<ul class="w-full m-0 pl-4 flex flex-col divide-y divide-gray-lighter"> | ||
<li | ||
:for={stop <- @leg.mode.intermediate_stops} | ||
class="inline-flex items-center gap-x-2 py-2 relative" | ||
> | ||
<.icon name="circle" class="w-2 h-2 absolute -left-6 fill-white" /> | ||
{stop.name} | ||
</li> | ||
</ul> | ||
""" | ||
end | ||
end |
Oops, something went wrong.