From 06df352257b2f388da64e0cb4df9be2fa807d58e Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Mon, 15 Jul 2019 15:46:15 -0400 Subject: [PATCH 01/10] Implement endpoint to fetch schedules as needed --- .../controllers/schedule/schedule_api.ex | 27 +++++++++++++++++++ apps/site/lib/site_web/router.ex | 1 + 2 files changed, 28 insertions(+) create mode 100644 apps/site/lib/site_web/controllers/schedule/schedule_api.ex diff --git a/apps/site/lib/site_web/controllers/schedule/schedule_api.ex b/apps/site/lib/site_web/controllers/schedule/schedule_api.ex new file mode 100644 index 0000000000..74317d2c86 --- /dev/null +++ b/apps/site/lib/site_web/controllers/schedule/schedule_api.ex @@ -0,0 +1,27 @@ +defmodule SiteWeb.ScheduleController.ScheduleApi do + use SiteWeb, :controller + + def show(conn, %{"id" => id, "date" => date, "direction_id" => direction_id}) do + {:ok, date} = Date.from_iso8601(date) + schedule_data = get_schedules(id, date, direction_id) + + json(conn, schedule_data) + end + + @spec get_schedules(binary, any, any) :: %{by_trip: map, trip_order: [any]} + def get_schedules(route_id, date, direction_id) do + services = + Enum.map( + Schedules.Repo.by_route_ids([route_id], date: date, direction_id: direction_id), + &Map.update!(&1, :route, fn route -> Routes.Route.to_json_safe(route) end) + ) + + services_by_trip = + services + |> Enum.map(&Map.update!(&1, :time, fn time -> Timex.format!(time, "{0h12}:{m} {AM}") end)) + |> Enum.group_by(& &1.trip.id) + + ordered_trips = services |> Enum.sort_by(& &1.time) |> Enum.map(& &1.trip.id) |> Enum.uniq() + %{by_trip: services_by_trip, trip_order: ordered_trips} + end +end diff --git a/apps/site/lib/site_web/router.ex b/apps/site/lib/site_web/router.ex index 26c51e77be..553f0e8c8b 100644 --- a/apps/site/lib/site_web/router.ex +++ b/apps/site/lib/site_web/router.ex @@ -109,6 +109,7 @@ defmodule SiteWeb.Router do get("/schedules", ModeController, :index) get("/schedules/predictions_api", ModeController, :predictions_api) + get("/schedules/schedule_api", ScheduleController.ScheduleApi, :show) get("/schedules/subway", ModeController, :subway) get("/schedules/bus", ModeController, :bus) get("/schedules/ferry", ModeController, :ferry) From 5cf9b51c493111d7968224f9338c21b10953ad6d Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Tue, 16 Jul 2019 14:46:32 -0400 Subject: [PATCH 02/10] Remove full schedule load from finder --- .../ts/schedule/components/ScheduleFinder.tsx | 1 - .../schedule-finder/ScheduleModalContent.tsx | 5 +--- .../schedule-finder/ServiceSelector.tsx | 7 +---- .../controllers/schedule/line_controller.ex | 29 ------------------- 4 files changed, 2 insertions(+), 40 deletions(-) diff --git a/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx b/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx index f425a70590..415f3ae8ae 100644 --- a/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx +++ b/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx @@ -263,7 +263,6 @@ const ScheduleFinder = ({ selectedOrigin={state.selectedOrigin} services={services} stops={stops} - serviceSchedules={serviceSchedules} /> )} diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx index a677e65552..6de4141de9 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx @@ -89,7 +89,6 @@ interface Props { selectedOrigin: SelectedOrigin; services: ServiceWithServiceDate[]; stops: SimpleStop[]; - serviceSchedules: ServiceSchedule; } const ScheduleModalContent = ({ @@ -103,8 +102,7 @@ const ScheduleModalContent = ({ selectedDirection, selectedOrigin, services, - stops, - serviceSchedules + stops }: Props): ReactElement | null => { const [state, dispatch] = useReducer(reducer, { data: null, @@ -139,7 +137,6 @@ const ScheduleModalContent = ({ diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index 3b735dfa88..01c6f019d1 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -29,7 +29,6 @@ const optGroupTitles: { [key in ServiceOptGroup]: string } = { interface Props { services: ServiceWithServiceDate[]; - serviceSchedules: ServiceSchedule; directionId: DirectionId; } @@ -102,12 +101,11 @@ const getTodaysScheduleId = ( const ServiceSelector = ({ services, - serviceSchedules, directionId }: Props): ReactElement | null => { const ref = useRef(null); const [state, setState] = useState({ selectedServiceId: "" }); - if (services.length <= 0 || Object.keys(serviceSchedules).length <= 0) + if (services.length <= 0) return null; const servicesByOptGroup: ServicesKeyedByGroup = services .map((service: ServiceWithServiceDate) => groupServiceByDate(service)) @@ -115,8 +113,6 @@ const ServiceSelector = ({ const defaultServiceId = getTodaysScheduleId(servicesByOptGroup); const selectedServiceId = state.selectedServiceId || defaultServiceId; - const selectedServiceSchedule = - serviceSchedules[selectedServiceId][directionId]; return ( <> @@ -155,7 +151,6 @@ const ServiceSelector = ({ - ); }; diff --git a/apps/site/lib/site_web/controllers/schedule/line_controller.ex b/apps/site/lib/site_web/controllers/schedule/line_controller.ex index cb70be365f..55f9b5b6c5 100644 --- a/apps/site/lib/site_web/controllers/schedule/line_controller.ex +++ b/apps/site/lib/site_web/controllers/schedule/line_controller.ex @@ -40,34 +40,6 @@ defmodule SiteWeb.ScheduleController.LineController do end end - @spec get_schedules(binary, any, any) :: %{by_trip: map, trip_order: [any]} - def get_schedules(route_id, date, direction_id) do - services = - Enum.map( - Schedules.Repo.by_route_ids([route_id], date: date, direction_id: direction_id), - &Map.update!(&1, :route, fn route -> Route.to_json_safe(route) end) - ) - - services_by_trip = - services - |> Enum.map(&Map.update!(&1, :time, fn time -> Timex.format!(time, "{0h12}:{m} {AM}") end)) - |> Enum.group_by(& &1.trip.id) - - ordered_trips = services |> Enum.sort_by(& &1.time) |> Enum.map(& &1.trip.id) |> Enum.uniq() - %{by_trip: services_by_trip, trip_order: ordered_trips} - end - - def schedules_for_service(route_id, services) do - services - |> Enum.reduce(%{}, fn %{start_date: date, id: service_id}, acc -> - Map.put(acc, service_id, %{ - service_id: service_id, - "0": get_schedules(route_id, date, 0), - "1": get_schedules(route_id, date, 1) - }) - end) - end - def assign_schedule_page_data(conn) do service_date = Util.service_date() services = Services.Repo.by_route_id(conn.assigns.route.id) @@ -101,7 +73,6 @@ defmodule SiteWeb.ScheduleController.LineController do services |> Enum.sort_by(&sort_services_by_date/1) |> Enum.map(&Map.put(&1, :service_date, service_date)), - service_schedules: schedules_for_service(conn.assigns.route.id, services), schedule_note: ScheduleNote.new(conn.assigns.route), stops: simple_stop_list(conn.assigns.all_stops), direction_id: conn.assigns.direction_id From 4d56d7843623ca1102f74c1d1e52c0b802b0d2b7 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Tue, 16 Jul 2019 16:35:13 -0400 Subject: [PATCH 03/10] Load schedules dynamically in finder --- .../schedule-finder/ScheduleModalContent.tsx | 1 + .../schedule-finder/ServiceSelector.tsx | 50 ++++++++++++++++--- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx index 6de4141de9..a262cbaaae 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx @@ -137,6 +137,7 @@ const ScheduleModalContent = ({ diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index 01c6f019d1..496857a39a 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement, useState, useRef } from "react"; +import React, { ReactElement, useEffect, useState, useRef } from "react"; import SelectContainer from "./SelectContainer"; import { ServiceWithServiceDate, @@ -13,7 +13,8 @@ import { ServiceOptGroup, ServiceByOptGroup, serviceDays, - hasMultipleWeekdaySchedules + hasMultipleWeekdaySchedules, + serviceDate } from "../../../helpers/service"; import { ServiceSchedule, ServiceScheduleInfo } from "../__schedule"; import { RoutePillSmall } from "./UpcomingDepartures"; @@ -29,6 +30,7 @@ const optGroupTitles: { [key in ServiceOptGroup]: string } = { interface Props { services: ServiceWithServiceDate[]; + routeId: string; directionId: DirectionId; } @@ -101,18 +103,50 @@ const getTodaysScheduleId = ( const ServiceSelector = ({ services, + routeId, directionId }: Props): ReactElement | null => { - const ref = useRef(null); - const [state, setState] = useState({ selectedServiceId: "" }); if (services.length <= 0) return null; + + const ref = useRef(null); + + const [selectedServiceId, setSelectedServiceId] = useState(""); + const [isLoading, setIsLoading] = useState(true) + const [selectedServiceSchedule, setSelectedServiceSchedule] = useState(null) + + const fetchSchedule = () => { + setIsLoading(true) + + var service = services.find((service) => service.id === selectedServiceId) + if(!service) { return; } + + window.fetch && + window.fetch( + `/schedules/schedule_api?id=${routeId}&date=${service.end_date}&direction_id=${directionId}` + ) + .then(response => { + setIsLoading(false) + if (response.ok) return response.json(); + throw new Error(response.statusText); + }) + .then(json => setSelectedServiceSchedule(json)) + } + + useEffect( + fetchSchedule, + [selectedServiceId] + ) + const servicesByOptGroup: ServicesKeyedByGroup = services .map((service: ServiceWithServiceDate) => groupServiceByDate(service)) .reduce(groupByType, { current: [], holiday: [], other: [] }); const defaultServiceId = getTodaysScheduleId(servicesByOptGroup); - const selectedServiceId = state.selectedServiceId || defaultServiceId; + + if(!selectedServiceId) { + setSelectedServiceId(defaultServiceId) + } return ( <> @@ -126,7 +160,7 @@ const ServiceSelector = ({ defaultValue={defaultServiceId} onChange={(): void => { if (ref && ref.current) { - setState({ selectedServiceId: ref.current.value }); + setSelectedServiceId(ref.current.value); } }} > @@ -151,6 +185,10 @@ const ServiceSelector = ({ + + {!isLoading && selectedServiceSchedule && + + } ); }; From 3d150ec734946b38ef76a2934705f762d6885082 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 17 Jul 2019 12:02:00 -0400 Subject: [PATCH 04/10] Improve frontend test coverage --- .../schedule/__tests__/ScheduleModalTest.tsx | 3 - .../__tests__/ServiceSelectorTest.tsx | 74 +- .../ServiceSelectorTest.tsx.snap | 5737 ----------------- .../schedule-finder/ServiceSelector.tsx | 50 +- 4 files changed, 101 insertions(+), 5763 deletions(-) diff --git a/apps/site/assets/ts/schedule/__tests__/ScheduleModalTest.tsx b/apps/site/assets/ts/schedule/__tests__/ScheduleModalTest.tsx index c85c25b160..c045ba39c6 100644 --- a/apps/site/assets/ts/schedule/__tests__/ScheduleModalTest.tsx +++ b/apps/site/assets/ts/schedule/__tests__/ScheduleModalTest.tsx @@ -87,7 +87,6 @@ describe("ScheduleModal", () => { selectedOrigin={stops[0].id} selectedDirection={0} services={[]} - serviceSchedules={{}} /> ); }); @@ -105,7 +104,6 @@ describe("ScheduleModal", () => { selectedOrigin={null} selectedDirection={0} services={[]} - serviceSchedules={{}} /> ); expect(tree!.toJSON()).toBeNull(); @@ -122,7 +120,6 @@ describe("ScheduleModal", () => { selectedOrigin={stops[0].id} selectedDirection={null} services={[]} - serviceSchedules={{}} /> ); expect(tree!.toJSON()).toBeNull(); diff --git a/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx b/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx index cf06ae7aa9..ef835fc14a 100644 --- a/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx +++ b/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx @@ -2,7 +2,7 @@ import React from "react"; import renderer from "react-test-renderer"; import { createReactRoot } from "../../app/helpers/testUtils"; import serviceData from "./serviceData.json"; -import ServiceSelector from "../components/schedule-finder/ServiceSelector"; +import { fetchSchedule, ServiceSelector } from "../components/schedule-finder/ServiceSelector"; import { ServiceSchedule } from "../components/__schedule.js"; import { ServiceWithServiceDate } from "../../__v3api"; @@ -138,9 +138,79 @@ describe("ServiceSelector", () => { ); expect(tree).toMatchSnapshot(); }); + + describe("fetchSchedule", () => { + it("fetches the selected schedule", async () => { + window.fetch = jest.fn().mockImplementation( + () => + new Promise((resolve: Function) => + resolve({ + json: () => { + return { + by_trip: "by_trip_data", + trip_order: "trip_order_data" + } + }, + ok: true, + status: 200, + statusText: "OK" + }) + ) + ); + + var loadingSpy = jest.fn() + var serviceScheduleSpy = jest.fn() + + await(await fetchSchedule(services, "BUS319-P-Sa-02", "83", 1, loadingSpy, serviceScheduleSpy)) + + expect(window.fetch).toHaveBeenCalledWith( + "/schedules/schedule_api?id=83&date=2019-08-31&direction_id=1" + ) + + expect(loadingSpy).toHaveBeenCalledTimes(2) + expect(loadingSpy).toHaveBeenCalledWith(true) + expect(loadingSpy).toHaveBeenLastCalledWith(false) + + expect(serviceScheduleSpy).toHaveBeenCalledTimes(1) + expect(serviceScheduleSpy).toHaveBeenCalledWith({by_trip: "by_trip_data", trip_order: "trip_order_data"}) + }), + + it("fails quietly if called with an invalid service ID", () => { + window.fetch = jest.fn() + var loadingSpy = jest.fn() + var serviceScheduleSpy = jest.fn() + + fetchSchedule(services, "BAD-SERVICE-ID", "83", 1, loadingSpy, serviceScheduleSpy) + expect(window.fetch).not.toHaveBeenCalled() + }), + + it("throws an error if the fetch fails", async () => { + window.fetch = jest.fn().mockImplementation( + () => + new Promise((resolve: Function) => + resolve({ + ok: false, + status: 500, + statusText: "you broke it" + }) + ) + ); + + var loadingSpy = jest.fn() + var serviceScheduleSpy = jest.fn() + + await fetchSchedule(services, "BUS319-P-Sa-02", "83", 1, loadingSpy, serviceScheduleSpy) + + expect(loadingSpy).toHaveBeenCalledTimes(2) + expect(loadingSpy).toHaveBeenCalledWith(true) + expect(loadingSpy).toHaveBeenLastCalledWith(false) + + expect(serviceScheduleSpy).not.toHaveBeenCalled() + }) + }); }); diff --git a/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap b/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap index 6a2c826002..3cf4ee81c3 100644 --- a/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap +++ b/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap @@ -72,5742 +72,5 @@ Array [ /> , -
-
- First Trip -
- 05:36 AM -
- Last Trip -
- 01:02 AM -
, - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Departs - - Destination -
- 05:36 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:46 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:55 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:03 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:10 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:17 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:24 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:31 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:37 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:43 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:49 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:54 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:59 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:03 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:05 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:09 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:10 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:13 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:14 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:19 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:21 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:24 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:26 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:27 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:32 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:33 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:37 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:39 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:42 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:44 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:46 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:50 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:51 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:55 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:57 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:59 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:01 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:03 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:07 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:08 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:12 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:15 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:17 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:21 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:22 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:25 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:26 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:31 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:33 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:35 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:38 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:39 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:43 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:45 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:48 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:51 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:53 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:56 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:57 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:03 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:05 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:09 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:13 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:14 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:20 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:23 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:27 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:31 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:33 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:39 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:40 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:50 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:05 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:17 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 10:20 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:35 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:44 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 10:50 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:56 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 11:05 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:20 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:35 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:50 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:53 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 12:05 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:08 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 12:14 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:24 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:34 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:36 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 12:44 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:54 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:02 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 01:04 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:14 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:23 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 01:24 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:32 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 01:34 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:44 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:54 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 02:04 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 02:14 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 02:24 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 02:33 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 02:38 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 02:43 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 02:53 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 03:02 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 03:12 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 03:23 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 03:32 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 03:42 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 03:45 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 03:52 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 03:53 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:01 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:03 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:09 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:13 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:19 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:22 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:24 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:27 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:31 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:33 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:38 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:39 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:43 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:45 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:48 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:51 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:53 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 04:54 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 04:58 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:00 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:03 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:06 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:08 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:12 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:13 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:18 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:20 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:23 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:27 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:28 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:32 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:33 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:38 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:41 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:43 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:47 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:48 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:53 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 05:55 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 05:58 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:01 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 06:02 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:07 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:09 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 06:12 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:16 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 06:17 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:22 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:23 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 06:27 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:32 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:37 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:42 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:47 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:52 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 06:57 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:02 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:06 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:12 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:17 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:23 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:25 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:29 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:38 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:46 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 07:49 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:53 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 07:59 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:09 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:18 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:25 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:38 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 08:48 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 08:51 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:04 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:17 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:30 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:43 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 09:48 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 09:56 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:09 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:12 PM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 10:22 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:35 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 10:48 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:01 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:14 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:29 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:44 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 11:59 PM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:14 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:24 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
- 12:30 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 12:50 AM - -
-
-
- SL2 -
-
-
- Drydock -
- 01:02 AM - -
-
-
- Silver Line Way - South Station -
-
-
- Silver Line Way -
, ] `; diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index 496857a39a..4cd93fb6b7 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement, useEffect, useState, useRef } from "react"; +import React, { Dispatch, ReactElement, SetStateAction, useEffect, useState, useRef } from "react"; import SelectContainer from "./SelectContainer"; import { ServiceWithServiceDate, @@ -101,7 +101,32 @@ const getTodaysScheduleId = ( return todayService ? todayService.service.id : ""; }; -const ServiceSelector = ({ +export const fetchSchedule = ( + services: ServiceWithServiceDate[], + selectedServiceId: string, + routeId: string, + directionId: DirectionId, + setIsLoading: Dispatch>, + setSelectedServiceSchedule: Dispatch> +) => { + setIsLoading(true) + + var service = services.find((service) => service.id === selectedServiceId) + if(!service) { return; } + + window.fetch && + window.fetch( + `/schedules/schedule_api?id=${routeId}&date=${service.end_date}&direction_id=${directionId}` + ) + .then(response => { + setIsLoading(false) + if (response.ok) return response.json(); + throw new Error(response.statusText); + }) + .then(json => setSelectedServiceSchedule(json)) +} + +export const ServiceSelector = ({ services, routeId, directionId @@ -115,26 +140,8 @@ const ServiceSelector = ({ const [isLoading, setIsLoading] = useState(true) const [selectedServiceSchedule, setSelectedServiceSchedule] = useState(null) - const fetchSchedule = () => { - setIsLoading(true) - - var service = services.find((service) => service.id === selectedServiceId) - if(!service) { return; } - - window.fetch && - window.fetch( - `/schedules/schedule_api?id=${routeId}&date=${service.end_date}&direction_id=${directionId}` - ) - .then(response => { - setIsLoading(false) - if (response.ok) return response.json(); - throw new Error(response.statusText); - }) - .then(json => setSelectedServiceSchedule(json)) - } - useEffect( - fetchSchedule, + () => fetchSchedule(services, selectedServiceId, routeId, directionId, setIsLoading, setSelectedServiceSchedule), [selectedServiceId] ) @@ -159,6 +166,7 @@ const ServiceSelector = ({ className="schedule-finder__select" defaultValue={defaultServiceId} onChange={(): void => { + /* istanbul ignore next */ if (ref && ref.current) { setSelectedServiceId(ref.current.value); } From cfa039a3d4e44a541ecea9cf2aaeab510ae0ce87 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 17 Jul 2019 13:29:31 -0400 Subject: [PATCH 05/10] Add dummy spinner --- .../__tests__/__snapshots__/ServiceSelectorTest.tsx.snap | 5 +++++ .../schedule/components/schedule-finder/ServiceSelector.tsx | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap b/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap index 3cf4ee81c3..7aadb8a814 100644 --- a/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap +++ b/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap @@ -72,5 +72,10 @@ Array [ /> , +
+ SPINNER GOES HERE +
, ] `; diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index 4cd93fb6b7..05e88acf7f 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -194,6 +194,8 @@ export const ServiceSelector = ({ + {isLoading &&
SPINNER GOES HERE
} + {!isLoading && selectedServiceSchedule && } From 70967039b77dbe8fa0ef788d854e6d33feea26e4 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 17 Jul 2019 15:00:04 -0400 Subject: [PATCH 06/10] Fix up formatting --- .../__tests__/ServiceSelectorTest.tsx | 119 ++++++++++-------- .../schedule-finder/ServiceSelector.tsx | 67 ++++++---- 2 files changed, 113 insertions(+), 73 deletions(-) diff --git a/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx b/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx index ef835fc14a..34e01e645d 100644 --- a/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx +++ b/apps/site/assets/ts/schedule/__tests__/ServiceSelectorTest.tsx @@ -2,7 +2,10 @@ import React from "react"; import renderer from "react-test-renderer"; import { createReactRoot } from "../../app/helpers/testUtils"; import serviceData from "./serviceData.json"; -import { fetchSchedule, ServiceSelector } from "../components/schedule-finder/ServiceSelector"; +import { + fetchSchedule, + ServiceSelector +} from "../components/schedule-finder/ServiceSelector"; import { ServiceSchedule } from "../components/__schedule.js"; import { ServiceWithServiceDate } from "../../__v3api"; @@ -135,11 +138,7 @@ describe("ServiceSelector", () => { it("it renders", () => { createReactRoot(); const tree = renderer.create( - + ); expect(tree).toMatchSnapshot(); }); @@ -154,7 +153,7 @@ describe("ServiceSelector", () => { return { by_trip: "by_trip_data", trip_order: "trip_order_data" - } + }; }, ok: true, status: 200, @@ -163,54 +162,76 @@ describe("ServiceSelector", () => { ) ); - var loadingSpy = jest.fn() - var serviceScheduleSpy = jest.fn() + var loadingSpy = jest.fn(); + var serviceScheduleSpy = jest.fn(); - await(await fetchSchedule(services, "BUS319-P-Sa-02", "83", 1, loadingSpy, serviceScheduleSpy)) + await await fetchSchedule( + services, + "BUS319-P-Sa-02", + "83", + 1, + loadingSpy, + serviceScheduleSpy + ); expect(window.fetch).toHaveBeenCalledWith( "/schedules/schedule_api?id=83&date=2019-08-31&direction_id=1" - ) - - expect(loadingSpy).toHaveBeenCalledTimes(2) - expect(loadingSpy).toHaveBeenCalledWith(true) - expect(loadingSpy).toHaveBeenLastCalledWith(false) - - expect(serviceScheduleSpy).toHaveBeenCalledTimes(1) - expect(serviceScheduleSpy).toHaveBeenCalledWith({by_trip: "by_trip_data", trip_order: "trip_order_data"}) - }), - - it("fails quietly if called with an invalid service ID", () => { - window.fetch = jest.fn() - var loadingSpy = jest.fn() - var serviceScheduleSpy = jest.fn() - - fetchSchedule(services, "BAD-SERVICE-ID", "83", 1, loadingSpy, serviceScheduleSpy) - expect(window.fetch).not.toHaveBeenCalled() - }), - - it("throws an error if the fetch fails", async () => { - window.fetch = jest.fn().mockImplementation( - () => - new Promise((resolve: Function) => - resolve({ - ok: false, - status: 500, - statusText: "you broke it" - }) - ) ); - var loadingSpy = jest.fn() - var serviceScheduleSpy = jest.fn() - - await fetchSchedule(services, "BUS319-P-Sa-02", "83", 1, loadingSpy, serviceScheduleSpy) + expect(loadingSpy).toHaveBeenCalledTimes(2); + expect(loadingSpy).toHaveBeenCalledWith(true); + expect(loadingSpy).toHaveBeenLastCalledWith(false); - expect(loadingSpy).toHaveBeenCalledTimes(2) - expect(loadingSpy).toHaveBeenCalledWith(true) - expect(loadingSpy).toHaveBeenLastCalledWith(false) - - expect(serviceScheduleSpy).not.toHaveBeenCalled() - }) + expect(serviceScheduleSpy).toHaveBeenCalledTimes(1); + expect(serviceScheduleSpy).toHaveBeenCalledWith({ + by_trip: "by_trip_data", + trip_order: "trip_order_data" + }); + }), + it("fails quietly if called with an invalid service ID", () => { + window.fetch = jest.fn(); + var loadingSpy = jest.fn(); + var serviceScheduleSpy = jest.fn(); + + fetchSchedule( + services, + "BAD-SERVICE-ID", + "83", + 1, + loadingSpy, + serviceScheduleSpy + ); + expect(window.fetch).not.toHaveBeenCalled(); + }), + it("throws an error if the fetch fails", async () => { + window.fetch = jest.fn().mockImplementation( + () => + new Promise((resolve: Function) => + resolve({ + ok: false, + status: 500, + statusText: "you broke it" + }) + ) + ); + + var loadingSpy = jest.fn(); + var serviceScheduleSpy = jest.fn(); + + await fetchSchedule( + services, + "BUS319-P-Sa-02", + "83", + 1, + loadingSpy, + serviceScheduleSpy + ); + + expect(loadingSpy).toHaveBeenCalledTimes(2); + expect(loadingSpy).toHaveBeenCalledWith(true); + expect(loadingSpy).toHaveBeenLastCalledWith(false); + + expect(serviceScheduleSpy).not.toHaveBeenCalled(); + }); }); }); diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index 05e88acf7f..ed18a6f34e 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -1,4 +1,11 @@ -import React, { Dispatch, ReactElement, SetStateAction, useEffect, useState, useRef } from "react"; +import React, { + Dispatch, + ReactElement, + SetStateAction, + useEffect, + useState, + useRef +} from "react"; import SelectContainer from "./SelectContainer"; import { ServiceWithServiceDate, @@ -109,41 +116,53 @@ export const fetchSchedule = ( setIsLoading: Dispatch>, setSelectedServiceSchedule: Dispatch> ) => { - setIsLoading(true) + setIsLoading(true); - var service = services.find((service) => service.id === selectedServiceId) - if(!service) { return; } + var service = services.find(service => service.id === selectedServiceId); + if (!service) { + return; + } window.fetch && - window.fetch( - `/schedules/schedule_api?id=${routeId}&date=${service.end_date}&direction_id=${directionId}` - ) - .then(response => { - setIsLoading(false) - if (response.ok) return response.json(); - throw new Error(response.statusText); - }) - .then(json => setSelectedServiceSchedule(json)) -} + window + .fetch( + `/schedules/schedule_api?id=${routeId}&date=${ + service.end_date + }&direction_id=${directionId}` + ) + .then(response => { + setIsLoading(false); + if (response.ok) return response.json(); + throw new Error(response.statusText); + }) + .then(json => setSelectedServiceSchedule(json)); +}; export const ServiceSelector = ({ services, routeId, directionId }: Props): ReactElement | null => { - if (services.length <= 0) - return null; + if (services.length <= 0) return null; const ref = useRef(null); const [selectedServiceId, setSelectedServiceId] = useState(""); - const [isLoading, setIsLoading] = useState(true) - const [selectedServiceSchedule, setSelectedServiceSchedule] = useState(null) + const [isLoading, setIsLoading] = useState(true); + const [selectedServiceSchedule, setSelectedServiceSchedule] = useState(null); useEffect( - () => fetchSchedule(services, selectedServiceId, routeId, directionId, setIsLoading, setSelectedServiceSchedule), + () => + fetchSchedule( + services, + selectedServiceId, + routeId, + directionId, + setIsLoading, + setSelectedServiceSchedule + ), [selectedServiceId] - ) + ); const servicesByOptGroup: ServicesKeyedByGroup = services .map((service: ServiceWithServiceDate) => groupServiceByDate(service)) @@ -151,8 +170,8 @@ export const ServiceSelector = ({ const defaultServiceId = getTodaysScheduleId(servicesByOptGroup); - if(!selectedServiceId) { - setSelectedServiceId(defaultServiceId) + if (!selectedServiceId) { + setSelectedServiceId(defaultServiceId); } return ( @@ -196,9 +215,9 @@ export const ServiceSelector = ({ {isLoading &&
SPINNER GOES HERE
} - {!isLoading && selectedServiceSchedule && + {!isLoading && selectedServiceSchedule && ( - } + )} ); }; From 540b56106f4ddad80ab2dc225644dcb4ae1d8704 Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Wed, 17 Jul 2019 15:20:12 -0400 Subject: [PATCH 07/10] Style fixes --- .../ts/schedule/components/ScheduleFinder.tsx | 3 +-- .../schedule-finder/ScheduleModalContent.tsx | 2 +- .../schedule-finder/ServiceSelector.tsx | 27 ++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx b/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx index 415f3ae8ae..1923751ae8 100644 --- a/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx +++ b/apps/site/assets/ts/schedule/components/ScheduleFinder.tsx @@ -58,8 +58,7 @@ const ScheduleFinder = ({ hideHeader, route, services, - stops, - serviceSchedules + stops }: Props): ReactElement => { const { direction_destinations: directionDestinations, diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx index a262cbaaae..744c0b00e9 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ScheduleModalContent.tsx @@ -2,7 +2,7 @@ import React, { ReactElement, useReducer, useEffect } from "react"; import { SelectedDirection, SelectedOrigin } from "../ScheduleFinder"; import UpcomingDepartures from "./UpcomingDepartures"; import { Route, RouteType, ServiceWithServiceDate } from "../../../__v3api"; -import { SimpleStop, StopPrediction, ServiceSchedule } from "../__schedule"; +import { SimpleStop, StopPrediction } from "../__schedule"; import isSilverLine from "../../../helpers/silver-line"; import ServiceSelector from "./ServiceSelector"; diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index ed18a6f34e..e26b683bea 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -20,10 +20,9 @@ import { ServiceOptGroup, ServiceByOptGroup, serviceDays, - hasMultipleWeekdaySchedules, - serviceDate + hasMultipleWeekdaySchedules } from "../../../helpers/service"; -import { ServiceSchedule, ServiceScheduleInfo } from "../__schedule"; +import { ServiceScheduleInfo } from "../__schedule"; import { RoutePillSmall } from "./UpcomingDepartures"; import { modeIcon } from "../../../helpers/icon"; @@ -114,20 +113,23 @@ export const fetchSchedule = ( routeId: string, directionId: DirectionId, setIsLoading: Dispatch>, - setSelectedServiceSchedule: Dispatch> -) => { + setSelectedServiceSchedule: Dispatch> +): void => { setIsLoading(true); - var service = services.find(service => service.id === selectedServiceId); - if (!service) { + const selectedService = services.find( + service => service.id === selectedServiceId + ); + + if (!selectedService) { return; } - window.fetch && + if (window.fetch) { window .fetch( `/schedules/schedule_api?id=${routeId}&date=${ - service.end_date + selectedService.end_date }&direction_id=${directionId}` ) .then(response => { @@ -136,6 +138,7 @@ export const fetchSchedule = ( throw new Error(response.statusText); }) .then(json => setSelectedServiceSchedule(json)); + } }; export const ServiceSelector = ({ @@ -143,8 +146,6 @@ export const ServiceSelector = ({ routeId, directionId }: Props): ReactElement | null => { - if (services.length <= 0) return null; - const ref = useRef(null); const [selectedServiceId, setSelectedServiceId] = useState(""); @@ -161,9 +162,11 @@ export const ServiceSelector = ({ setIsLoading, setSelectedServiceSchedule ), - [selectedServiceId] + [services, directionId, routeId, selectedServiceId] ); + if (services.length <= 0) return null; + const servicesByOptGroup: ServicesKeyedByGroup = services .map((service: ServiceWithServiceDate) => groupServiceByDate(service)) .reduce(groupByType, { current: [], holiday: [], other: [] }); From 84e61eae131ce568931d6ffbc7c2b601d2296efa Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 18 Jul 2019 12:06:13 -0400 Subject: [PATCH 08/10] Rename param --- apps/site/lib/site_web/controllers/schedule/schedule_api.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/site/lib/site_web/controllers/schedule/schedule_api.ex b/apps/site/lib/site_web/controllers/schedule/schedule_api.ex index 74317d2c86..b0585d6e9b 100644 --- a/apps/site/lib/site_web/controllers/schedule/schedule_api.ex +++ b/apps/site/lib/site_web/controllers/schedule/schedule_api.ex @@ -1,9 +1,9 @@ defmodule SiteWeb.ScheduleController.ScheduleApi do use SiteWeb, :controller - def show(conn, %{"id" => id, "date" => date, "direction_id" => direction_id}) do + def show(conn, %{"id" => route_id, "date" => date, "direction_id" => direction_id}) do {:ok, date} = Date.from_iso8601(date) - schedule_data = get_schedules(id, date, direction_id) + schedule_data = get_schedules(route_id, date, direction_id) json(conn, schedule_data) end From 0d31909c3c77533002edb8afd0ef54e6ac61a9aa Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 18 Jul 2019 12:14:09 -0400 Subject: [PATCH 09/10] Rename var --- .../lib/site_web/controllers/schedule/schedule_api.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/site/lib/site_web/controllers/schedule/schedule_api.ex b/apps/site/lib/site_web/controllers/schedule/schedule_api.ex index b0585d6e9b..4e43c0cf4d 100644 --- a/apps/site/lib/site_web/controllers/schedule/schedule_api.ex +++ b/apps/site/lib/site_web/controllers/schedule/schedule_api.ex @@ -10,18 +10,18 @@ defmodule SiteWeb.ScheduleController.ScheduleApi do @spec get_schedules(binary, any, any) :: %{by_trip: map, trip_order: [any]} def get_schedules(route_id, date, direction_id) do - services = + schedules = Enum.map( Schedules.Repo.by_route_ids([route_id], date: date, direction_id: direction_id), &Map.update!(&1, :route, fn route -> Routes.Route.to_json_safe(route) end) ) - services_by_trip = - services + schedules_by_trip = + schedules |> Enum.map(&Map.update!(&1, :time, fn time -> Timex.format!(time, "{0h12}:{m} {AM}") end)) |> Enum.group_by(& &1.trip.id) - ordered_trips = services |> Enum.sort_by(& &1.time) |> Enum.map(& &1.trip.id) |> Enum.uniq() - %{by_trip: services_by_trip, trip_order: ordered_trips} + ordered_trips = schedules |> Enum.sort_by(& &1.time) |> Enum.map(& &1.trip.id) |> Enum.uniq() + %{by_trip: schedules_by_trip, trip_order: ordered_trips} end end From 7afd5f87523fc441bbd2c8e80424279b034b505b Mon Sep 17 00:00:00 2001 From: Phil Darnowsky Date: Thu, 18 Jul 2019 12:33:03 -0400 Subject: [PATCH 10/10] Add real but placeholder spinner --- apps/site/assets/css/_schedule-page.scss | 48 +++++++++++++++++++ .../ServiceSelectorTest.tsx.snap | 4 +- .../schedule-finder/ServiceSelector.tsx | 2 +- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/apps/site/assets/css/_schedule-page.scss b/apps/site/assets/css/_schedule-page.scss index 061a00b516..e35ef51ec5 100644 --- a/apps/site/assets/css/_schedule-page.scss +++ b/apps/site/assets/css/_schedule-page.scss @@ -370,3 +370,51 @@ justify-content: space-evenly; padding: $base-spacing / 2; } + +.schedule-finder__spinner, +.schedule-finder__spinner::before, +.schedule-finder__spinner::after { + animation: load7 1.8s infinite ease-in-out; + animation-fill-mode: both; + border-radius: 50%; + height: 2.5em; + width: 2.5em; +} + +.schedule-finder__spinner { + animation-delay: -.16s; + color: $brand-primary; + font-size: 10px; + margin: 80px auto; + position: relative; + text-indent: -9999em; + transform: translateZ(0); +} + +.schedule-finder__spinner::before, +.schedule-finder__spinner::after { + content: ''; + position: absolute; + top: 0; +} + +.schedule-finder__spinner::before { + animation-delay: -.32s; + left: -3.5em; +} + +.schedule-finder__spinner::after { + left: 3.5em; +} + +@keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + + 40% { + box-shadow: 0 2.5em 0 0; + } +} diff --git a/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap b/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap index 7aadb8a814..590fa2acce 100644 --- a/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap +++ b/apps/site/assets/ts/schedule/__tests__/__snapshots__/ServiceSelectorTest.tsx.snap @@ -73,9 +73,9 @@ Array [ ,
- SPINNER GOES HERE + Loading...
, ] `; diff --git a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx index e26b683bea..b91222e44a 100644 --- a/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx +++ b/apps/site/assets/ts/schedule/components/schedule-finder/ServiceSelector.tsx @@ -216,7 +216,7 @@ export const ServiceSelector = ({ - {isLoading &&
SPINNER GOES HERE
} + {isLoading &&
Loading...
} {!isLoading && selectedServiceSchedule && (