From 0fb74f0cb1ea4c3006fc732da1f8f63f0fa6b058 Mon Sep 17 00:00:00 2001 From: Sky Rose Date: Fri, 13 Sep 2019 13:34:57 -0400 Subject: [PATCH] Hardcoded shuttle runs (#193) * helpers/array.ts uniq * known shuttles list --- assets/css/_route_picker.scss | 9 +- assets/css/_ui_kit.scss | 29 +++- assets/src/components/routePicker.tsx | 2 +- assets/src/components/shuttlePicker.tsx | 99 +++++++++--- assets/src/helpers/array.ts | 2 + .../__snapshots__/ladderPage.test.tsx.snap | 6 +- .../__snapshots__/routePicker.test.tsx.snap | 6 +- .../shuttleMapPage.test.tsx.snap | 146 +++++++++++++++++- .../__snapshots__/shuttlePicker.test.tsx.snap | 70 ++++++++- .../tests/components/shuttlePicker.test.tsx | 49 +++++- assets/tests/helpers/array.test.ts | 24 ++- 11 files changed, 395 insertions(+), 47 deletions(-) diff --git a/assets/css/_route_picker.scss b/assets/css/_route_picker.scss index fd483fd62..a9c4f8f1d 100644 --- a/assets/css/_route_picker.scss +++ b/assets/css/_route_picker.scss @@ -31,7 +31,6 @@ } .m-route-picker__route-list-button { - @include button-light; margin-bottom: 0.25rem; width: 100%; word-break: break-word; @@ -39,4 +38,12 @@ &--selected { @include button-primary; } + + &--unselected { + @include button-light; + } + + &--disabled { + @include button-disabled; + } } diff --git a/assets/css/_ui_kit.scss b/assets/css/_ui_kit.scss index d9b2ed69f..2ad6724a1 100644 --- a/assets/css/_ui_kit.scss +++ b/assets/css/_ui_kit.scss @@ -17,6 +17,13 @@ $color-secondary-dark: #4db6ac; $color-secondary-medium: #b8dbd9; $color-secondary-light: #d4e7e7; +$color-button-simple: $color-component-light; +$color-button-primary: $color-primary; +$color-button-secondary: $color-secondary-dark; +$color-button-light: $color-bg-base; +$color-button-disabled: #e6e8ec; +$color-button-focus: $color-secondary-medium; + $color-font-dark: $color-component-dark; $color-font-grey: $color-component-medium; $color-font-link: $color-secondary-dark; @@ -113,23 +120,23 @@ $color-line-gapped-light: #75e8ff; &:focus, &:hover { - background-color: $color-secondary-medium; + background-color: $color-button-focus; } } @mixin button-simple { @include button-base; - background-color: $color-component-light; + background-color: $color-button-simple; } @mixin button-light { @include button-base; - background-color: $color-bg-base; + background-color: $color-button-light; } @mixin button-primary { @include button-base; - background-color: $color-primary; + background-color: $color-button-primary; color: $color-font-light; &:focus, @@ -140,7 +147,19 @@ $color-line-gapped-light: #75e8ff; @mixin button-secondary { @include button-base; - background-color: $color-secondary-dark; + background-color: $color-button-secondary; +} + +@mixin button-disabled { + @include button-base; + background-color: $color-button-disabled; + color: $color-font-grey; + cursor: default; + + &:focus, + &:hover { + background-color: $color-button-disabled; + } } @mixin button-icon($size) { diff --git a/assets/src/components/routePicker.tsx b/assets/src/components/routePicker.tsx index f35c6601d..bd90da920 100644 --- a/assets/src/components/routePicker.tsx +++ b/assets/src/components/routePicker.tsx @@ -93,7 +93,7 @@ const RouteListButton = ({ const [, dispatch] = useContext(StateDispatchContext) const selectedClass = isSelected ? "m-route-picker__route-list-button--selected" - : "" + : "m-route-picker__route-list-button--unselected" const clickHandler = isSelected ? () => dispatch(deselectRoute(route.id)) : () => dispatch(selectRoute(route.id)) diff --git a/assets/src/components/shuttlePicker.tsx b/assets/src/components/shuttlePicker.tsx index 7e9bc01da..9e2b74df9 100644 --- a/assets/src/components/shuttlePicker.tsx +++ b/assets/src/components/shuttlePicker.tsx @@ -1,52 +1,115 @@ import React, { ReactElement, useContext } from "react" import { ShuttleVehiclesContext } from "../contexts/shuttleVehiclesContext" import { StateDispatchContext } from "../contexts/stateDispatchContext" -import { Vehicle } from "../realtime" +import { uniq } from "../helpers/array" +import { RunId, Vehicle } from "../realtime" import { deselectShuttleRun, selectShuttleRun } from "../state" +interface KnownShuttle { + name: string + runId: RunId +} + +const KNOWN_SHUTTLES: KnownShuttle[] = [ + { + name: "Special", + runId: "999-0555", + }, + { + name: "Blue", + runId: "999-0501", + }, + { + name: "Green", + runId: "999-0502", + }, + { + name: "Orange", + runId: "999-0503", + }, + { + name: "Red", + runId: "999-0504", + }, + { + name: "Commuter Rail", + runId: "999-0505", + }, +] + +const KNOWN_RUN_IDS: RunId[] = KNOWN_SHUTTLES.map( + knownShuttle => knownShuttle.runId +) + const ShuttlePicker = ({}): ReactElement => { - const shuttles = useContext(ShuttleVehiclesContext) + const shuttles: Vehicle[] = useContext(ShuttleVehiclesContext) + const activeRunIds: RunId[] = uniq(shuttles + .map(v => v.runId) + .filter(runId => runId !== null) as RunId[]) + return (
Run #
    - {renderRunIdButtons(shuttles)} + {KNOWN_SHUTTLES.map(knownShuttle => ( + + ))} + {activeRunIds.map(runId => + KNOWN_RUN_IDS.includes(runId) ? null : ( + + ) + )}
) } -const renderRunIdButtons = ( - shuttles: Vehicle[] -): Array> => - Array.from(new Set(shuttles.map(v => v.runId).sort())).map(runId => ( - - )) - const RunIdButton = ({ + name, runId, + isActive, }: { - runId: string + name: string + runId: RunId + isActive: boolean }): ReactElement => { const [state, dispatch] = useContext(StateDispatchContext) const isSelected = state.selectedShuttleRunIds.includes(runId) - const selectedClass = isSelected - ? "m-route-picker__route-list-button--selected" - : "" + const selectedClass = isActive + ? isSelected + ? "m-route-picker__route-list-button--selected" + : "m-route-picker__route-list-button--unselected" + : "m-route-picker__route-list-button--disabled" - const onClick = isSelected - ? () => dispatch(deselectShuttleRun(runId)) - : () => dispatch(selectShuttleRun(runId)) + const onClick = isActive + ? isSelected + ? () => dispatch(deselectShuttleRun(runId)) + : () => dispatch(selectShuttleRun(runId)) + : // tslint:disable-next-line: no-empty + () => {} return (
  • ) } +export const formatRunId = (runId: RunId): string => runId.replace(/-0*/, " ") + export default ShuttlePicker diff --git a/assets/src/helpers/array.ts b/assets/src/helpers/array.ts index 7e9170272..a61507401 100644 --- a/assets/src/helpers/array.ts +++ b/assets/src/helpers/array.ts @@ -6,3 +6,5 @@ export function partition(items: T[], testFn: (value: T) => boolean): T[][] { [[] as T[], [] as T[]] ) } + +export const uniq = (array: T[]): T[] => Array.from(new Set(array)).sort() diff --git a/assets/tests/components/__snapshots__/ladderPage.test.tsx.snap b/assets/tests/components/__snapshots__/ladderPage.test.tsx.snap index 6c3cc6175..da4e3c7d9 100644 --- a/assets/tests/components/__snapshots__/ladderPage.test.tsx.snap +++ b/assets/tests/components/__snapshots__/ladderPage.test.tsx.snap @@ -169,7 +169,7 @@ exports[`LadderPage renders with routes 1`] = `
  • +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • +
  • @@ -100,9 +146,55 @@ exports[`Shuttle Map Page renders a selected shuttle vehicle 1`] = `
  • +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • +
  • @@ -337,9 +429,55 @@ exports[`Shuttle Map Page renders selected shuttle routes 1`] = `
  • +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • +
  • diff --git a/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap b/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap index 8bc4b9f74..f67939e42 100644 --- a/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap +++ b/assets/tests/components/__snapshots__/shuttlePicker.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ShuttlePicker renders a list of runs 1`] = ` +exports[`ShuttlePicker renders 1`] = `
    @@ -14,10 +14,74 @@ exports[`ShuttlePicker renders a list of runs 1`] = ` >
  • +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • +
  • diff --git a/assets/tests/components/shuttlePicker.test.tsx b/assets/tests/components/shuttlePicker.test.tsx index ccac7c4d0..715af433c 100644 --- a/assets/tests/components/shuttlePicker.test.tsx +++ b/assets/tests/components/shuttlePicker.test.tsx @@ -1,11 +1,11 @@ import { mount } from "enzyme" import React from "react" import renderer from "react-test-renderer" -import ShuttlePicker from "../../src/components/shuttlePicker" +import ShuttlePicker, { formatRunId } from "../../src/components/shuttlePicker" import { ShuttleVehiclesProvider } from "../../src/contexts/shuttleVehiclesContext" import { StateDispatchProvider } from "../../src/contexts/stateDispatchContext" import { HeadwaySpacing } from "../../src/models/vehicleStatus" -import { Vehicle } from "../../src/realtime" +import { RunId, Vehicle } from "../../src/realtime" import { deselectShuttleRun, initialState, @@ -54,11 +54,34 @@ const vehicle: Vehicle = { } describe("ShuttlePicker", () => { - test("renders a list of runs", () => { + test("renders", () => { + /* + 999-0501: known, no active shuttles, unselected + 999-0502: known, no active shuttles, selected + 999-0503: known, active shuttles, unselected + 999-0504: known, active shuttles, selected + 999-0511: unknown, unselected + 999-0512: unknown, selected + */ + const selectedShuttleRunIds: RunId[] = ["999-0502", "999-0504", "999-0512"] + const shuttles: Vehicle[] = [ + { ...vehicle, runId: "999-0503" }, + { ...vehicle, runId: "999-0504" }, + { ...vehicle, runId: "999-0511" }, + { ...vehicle, runId: "999-0512" }, + ] const tree = renderer.create( - - - + + + + + ) expect(tree).toMatchSnapshot() @@ -74,7 +97,7 @@ describe("ShuttlePicker", () => { ) wrapper - .find(".m-route-picker__route-list-button") + .find(".m-route-picker__route-list-button--unselected") .first() .simulate("click") @@ -94,10 +117,20 @@ describe("ShuttlePicker", () => { ) wrapper - .find(".m-route-picker__route-list-button") + .find(".m-route-picker__route-list-button--selected") .first() .simulate("click") expect(dispatch).toHaveBeenCalledWith(deselectShuttleRun(vehicle.runId!)) }) }) + +describe("formatRunId", () => { + test("removes -", () => { + expect(formatRunId("999-1234")).toEqual("999 1234") + }) + + test("removes leading 0s", () => { + expect(formatRunId("999-0550")).toEqual("999 550") + }) +}) diff --git a/assets/tests/helpers/array.test.ts b/assets/tests/helpers/array.test.ts index f721cfe7a..d041adaf7 100644 --- a/assets/tests/helpers/array.test.ts +++ b/assets/tests/helpers/array.test.ts @@ -1,4 +1,4 @@ -import { partition } from "../../src/helpers/array" +import { partition, uniq } from "../../src/helpers/array" describe("partition", () => { test("partitions elements that the test function evaluates to true into the first bucket, else to the second bucket", () => { @@ -11,3 +11,25 @@ describe("partition", () => { expect(partition(numbers, isOddFn)).toEqual([oddNumbers, evenNumbers]) }) }) + +describe("uniq", () => { + test("empty case", () => { + expect(uniq([])).toEqual([]) + }) + + test("removes duplicate values", () => { + expect(uniq(["1", "1"])).toEqual(["1"]) + }) + + test("keeps different values", () => { + expect(uniq(["1", "2"])).toEqual(["1", "2"]) + }) + + test("sorts output", () => { + expect(uniq(["2", "1"])).toEqual(["1", "2"]) + }) + + test("removes duplicate values even if they're not next to each other", () => { + expect(uniq(["1", "3", "2", "3", "1", "1"])).toEqual(["1", "2", "3"]) + }) +})