Five UI and data features for return journeys and results page
- Replace native date inputs with always-open custom calendar; return journeys show two months side-by-side with Airbnb-style range selection - Add min-connection filter (30/40/50/60 min) for the inbound leg of return journeys, separate from the outbound connection filter - Fix total journey time: naive datetime subtraction across CET/BST was 1 h too long outbound and 1 h too short inbound - Filter inbound circle line suggestions when connection ≥ 40 min: only show services arriving ≥ 5 min before GWR departure at Paddington - Add Std / SP labels to Eurostar fare lines so users can distinguish Standard from Standard Premier - Row selection with a fixed summary bar showing NR + Eurostar + circle totals; selection is preserved in the URL - Load walk-on fares sequentially, outbound section first - Mobile: card-grid table layout, hide headcode/platform on small screens Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a88b19fa4c
commit
1bc7631863
5 changed files with 695 additions and 122 deletions
|
|
@ -44,11 +44,24 @@ def _circle_line_services(arrive_paddington: datetime) -> list[dict]:
|
|||
]
|
||||
|
||||
|
||||
def _circle_line_services_to_paddington(arrive_st_pancras: datetime) -> list[dict]:
|
||||
PAD_WALK_FROM_UNDERGROUND_MINUTES = 5 # Circle line platform → GWR platform at Paddington
|
||||
INBOUND_COMFORTABLE_MIN_CONN = 40 # threshold above which we apply the platform walk buffer
|
||||
|
||||
|
||||
def _circle_line_services_to_paddington(
|
||||
arrive_st_pancras: datetime,
|
||||
dep_paddington: datetime | None = None,
|
||||
min_conn_minutes: int = INBOUND_MIN_CONNECTION_MINUTES,
|
||||
) -> list[dict]:
|
||||
earliest_board = arrive_st_pancras + timedelta(
|
||||
minutes=KX_WALK_TO_UNDERGROUND_MINUTES
|
||||
)
|
||||
services = circle_line.upcoming_services(earliest_board, count=1, direction='kx_to_pad', preceding=1)
|
||||
if min_conn_minutes >= INBOUND_COMFORTABLE_MIN_CONN and dep_paddington is not None:
|
||||
cutoff = dep_paddington - timedelta(minutes=PAD_WALK_FROM_UNDERGROUND_MINUTES)
|
||||
candidates = circle_line.upcoming_services(earliest_board, count=4, direction='kx_to_pad')
|
||||
services = [(dep, arr) for dep, arr in candidates if arr <= cutoff][:2]
|
||||
else:
|
||||
services = circle_line.upcoming_services(earliest_board, count=1, direction='kx_to_pad', preceding=1)
|
||||
return [
|
||||
{
|
||||
"depart": dep.strftime(TIME_FMT),
|
||||
|
|
@ -166,8 +179,8 @@ def combine_trips(
|
|||
continue
|
||||
dep_bri, arr_pad, dep_stp, arr_dest = connection
|
||||
|
||||
total_mins = int((arr_dest - dep_bri).total_seconds() / 60)
|
||||
# Destination time is CET/CEST, departure is GMT/BST; Europe is always 1h ahead.
|
||||
total_mins = int((arr_dest - dep_bri).total_seconds() / 60) - 60
|
||||
eurostar_mins = int((arr_dest - dep_stp).total_seconds() / 60) - 60
|
||||
fare = (gwr_fares or {}).get(gwr["depart_bristol"])
|
||||
circle_svcs = _circle_line_services(arr_pad)
|
||||
|
|
@ -226,11 +239,11 @@ def combine_inbound_trips(
|
|||
if not connection:
|
||||
continue
|
||||
dep_dest, arr_stp, dep_pad, arr_station = connection
|
||||
total_mins = int((arr_station - dep_dest).total_seconds() / 60)
|
||||
# Destination time is CET/CEST, arrival at London is GMT/BST.
|
||||
# Destination time is CET/CEST, arrival at London is GMT/BST; Europe is always 1h ahead.
|
||||
total_mins = int((arr_station - dep_dest).total_seconds() / 60) + 60
|
||||
eurostar_mins = int((arr_stp - dep_dest).total_seconds() / 60) + 60
|
||||
fare = (gwr_fares or {}).get(gwr["depart_paddington"])
|
||||
circle_svcs = _circle_line_services_to_paddington(arr_stp)
|
||||
circle_svcs = _circle_line_services_to_paddington(arr_stp, dep_pad, min_connection_minutes)
|
||||
trips.append(
|
||||
{
|
||||
"direction": "inbound",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue