Skip to content

Commit

Permalink
feat(ts/hooks/usePanelState): add setTabMode API
Browse files Browse the repository at this point in the history
  • Loading branch information
firestack committed Nov 8, 2023
1 parent 364530f commit 0fde39e
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 111 deletions.
18 changes: 16 additions & 2 deletions assets/src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import MapPage from "./mapPage"
import SearchPage from "./searchPage"
import { OpenView, isPagePath } from "../state/pagePanelState"
import { usePanelStateFromStateDispatchContext } from "../hooks/usePanelState"
import PropertiesPanel from "./propertiesPanel"
import { isVehicleInScheduledService } from "../models/vehicle"

export const AppRoutes = () => {
useAppcues()
Expand All @@ -36,6 +38,8 @@ export const AppRoutes = () => {

const {
setPath,
setTabMode,
closeView,
currentView: { openView, selectedVehicleOrGhost, vppTabMode },
} = usePanelStateFromStateDispatchContext()

Expand Down Expand Up @@ -73,8 +77,18 @@ export const AppRoutes = () => {
<>
<Outlet />
<RightPanel
selectedVehicleOrGhost={selectedVehicleOrGhost}
initialTab={vppTabMode}
openView={openView}
propertiesPanel={
selectedVehicleOrGhost &&
isVehicleInScheduledService(selectedVehicleOrGhost) ? (
<PropertiesPanel
selectedVehicleOrGhost={selectedVehicleOrGhost}
tabMode={vppTabMode ?? "status"}
onChangeTabMode={setTabMode}
onClosePanel={closeView}
/>
) : undefined
}
/>
</>
}
Expand Down
42 changes: 15 additions & 27 deletions assets/src/components/rightPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,30 @@
import React, { ReactElement } from "react"
import { Ghost, Vehicle } from "../realtime.d"
import React, { ReactElement, ReactNode } from "react"
import NotificationDrawer from "./notificationDrawer"
import PropertiesPanel from "./propertiesPanel"
import SwingsView from "./swingsView"
import { OpenView } from "../state/pagePanelState"
import { usePanelStateFromStateDispatchContext } from "../hooks/usePanelState"
import { TabMode } from "./propertiesPanel/tabPanels"
import LateView from "./lateView"

const RightPanel = ({
selectedVehicleOrGhost,
initialTab,
}: {
selectedVehicleOrGhost?: Vehicle | Ghost | null
initialTab?: TabMode
}): ReactElement<HTMLElement> | null => {
const {
currentView: { openView },
closeView,
} = usePanelStateFromStateDispatchContext()
type RightPanelProps = {
openView: OpenView
propertiesPanel?: ReactNode
}

if (selectedVehicleOrGhost) {
return (
<PropertiesPanel.WithTabState
selectedVehicleOrGhost={selectedVehicleOrGhost}
onClosePanel={closeView}
initialTab={initialTab}
/>
)
} else if (openView === OpenView.Swings) {
const RightPanel = ({
openView,
propertiesPanel,
}: RightPanelProps): ReactElement | null => {
if (propertiesPanel !== undefined) {
return <>{propertiesPanel}</>
}
if (openView === OpenView.Swings) {
return <SwingsView />
} else if (openView === OpenView.Late) {
return <LateView />
} else if (openView === OpenView.NotificationDrawer) {
return <NotificationDrawer />
} else {
return null
}

return null
}

export default RightPanel
6 changes: 6 additions & 0 deletions assets/src/hooks/usePanelState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ export const usePanelStateForViewState = (
})
}
},
setTabMode(tabMode: TabMode) {
dispatch({
type: "SET_TAB_MODE",
payload: { tabMode },
})
},
openVehiclePropertiesPanel: (vehicle: VehicleType, initialView?: TabMode) =>
dispatch({
type: "SELECT_VEHICLE",
Expand Down
14 changes: 14 additions & 0 deletions assets/src/state/pagePanelState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ const openViewPanelReducer = (
vppTabMode,
}
}
case "SET_TAB_MODE": {
return state.selectedVehicleOrGhost
? {
...state,
vppTabMode: action.payload.tabMode,
}
: state
}
case "OPEN_NOTIFICATION_DRAWER":
return openView === OpenView.NotificationDrawer
? state
Expand Down Expand Up @@ -183,6 +191,7 @@ export type PanelViewAction =
// Vehicles
| SelectVehicleAction
| SelectVehicleFromNotificationAction
| SetVppTabMode
// Views
| OpenNotificationDrawerAction
| OpenSwingsViewAction
Expand All @@ -195,6 +204,11 @@ interface SetCurrentPath {
path: PagePath
}

interface SetVppTabMode {
type: "SET_TAB_MODE"
payload: { tabMode: TabMode }
}

interface SelectVehicleAction {
type: "SELECT_VEHICLE"
payload: {
Expand Down
95 changes: 13 additions & 82 deletions assets/tests/components/rightPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,14 @@ import { BrowserRouter } from "react-router-dom"
import "@testing-library/jest-dom/jest-globals"
import renderer from "react-test-renderer"
import RightPanel from "../../src/components/rightPanel"
import { StateDispatchProvider } from "../../src/contexts/stateDispatchContext"
import { State } from "../../src/state"
import * as dateTime from "../../src/util/dateTime"

import ghostFactory from "../factories/ghost"
import vehicleFactory from "../factories/vehicle"
import stateFactory from "../factories/applicationState"
import { RunFactory } from "../factories/run"
import { OpenView } from "../../src/state/pagePanelState"
import { viewFactory } from "../factories/pagePanelStateFactory"

const ghost = ghostFactory.build({ runId: "ghostrun-1" })
const vehicle = vehicleFactory.build()

jest
.spyOn(dateTime, "now")
Expand All @@ -30,7 +25,7 @@ describe("rightPanel", () => {
const tree = renderer
.create(
<BrowserRouter>
<RightPanel />
<RightPanel openView={OpenView.None} />
</BrowserRouter>
)
.toJSON()
Expand All @@ -40,112 +35,48 @@ describe("rightPanel", () => {
test("shows a selected vehicle", () => {
const { id: runId } = RunFactory.build()
const vehicle = vehicleFactory.build({ runId })
const state = stateFactory.build({
view: viewFactory
.currentState({ selectedVehicleOrGhost: vehicle })
.build(),
})

const result = render(
<StateDispatchProvider state={state} dispatch={jest.fn()}>
<BrowserRouter>
<RightPanel selectedVehicleOrGhost={vehicle} />
</BrowserRouter>
</StateDispatchProvider>
<RightPanel
openView={OpenView.None}
propertiesPanel={<button>{vehicle.runId!}</button>}
/>
)

expect(result.queryByRole("button", { name: vehicle.runId! })).toBeVisible()
})

test("shows a selected ghost", () => {
const state: State = stateFactory.build({
view: viewFactory
.currentState({
selectedVehicleOrGhost: ghost,
})
.build(),
})
const result = render(
<StateDispatchProvider state={state} dispatch={jest.fn()}>
<BrowserRouter>
<RightPanel selectedVehicleOrGhost={ghost} />
</BrowserRouter>
</StateDispatchProvider>
<RightPanel openView={OpenView.None} propertiesPanel={ghost.runId!} />
)
expect(result.queryByText(ghost.runId!)).toBeVisible()
})

test("shows notification drawer", () => {
const state: State = stateFactory.build({
view: viewFactory
.currentState({
openView: OpenView.NotificationDrawer,
})
.build(),
})
const result = render(
<StateDispatchProvider state={state} dispatch={jest.fn()}>
<BrowserRouter>
<RightPanel />
</BrowserRouter>
</StateDispatchProvider>
)
const result = render(<RightPanel openView={OpenView.NotificationDrawer} />)
expect(result.getByText("Notifications")).toBeVisible()
})

test("prefers VPP to notification drawer", () => {
const state: State = stateFactory.build({
view: viewFactory
.withVehicle()
.currentState({
openView: OpenView.NotificationDrawer,
})
.build(),
})
const result = render(
<StateDispatchProvider state={state} dispatch={jest.fn()}>
<BrowserRouter>
<RightPanel selectedVehicleOrGhost={vehicle} />
</BrowserRouter>
</StateDispatchProvider>
<RightPanel
openView={OpenView.NotificationDrawer}
propertiesPanel="Vehicles"
/>
)
expect(result.queryByText("Vehicles")).toBeVisible()
expect(result.queryByText("Notifications")).toBeNull()
})

test("shows swings view", () => {
const state: State = stateFactory.build({
view: viewFactory
.currentState({
openView: OpenView.Swings,
})
.build(),
})
const result = render(
<StateDispatchProvider state={state} dispatch={jest.fn()}>
<BrowserRouter>
<RightPanel />
</BrowserRouter>
</StateDispatchProvider>
)
const result = render(<RightPanel openView={OpenView.Swings} />)
expect(result.queryByText("Swings")).toBeVisible()
})

test("prefers VPP to swings view", () => {
const state: State = stateFactory.build({
view: viewFactory
.currentState({
selectedVehicleOrGhost: vehicle,
openView: OpenView.Swings,
})
.build(),
})
const result = render(
<StateDispatchProvider state={state} dispatch={jest.fn()}>
<BrowserRouter>
<RightPanel selectedVehicleOrGhost={vehicle} />
</BrowserRouter>
</StateDispatchProvider>
<RightPanel openView={OpenView.Swings} propertiesPanel="Vehicles" />
)
expect(result.queryByText("Vehicles")).toBeVisible()
expect(result.queryByText("Swings")).toBeNull()
Expand Down
1 change: 1 addition & 0 deletions assets/tests/testHelpers/usePanelStateMocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function mockUsePanelState(
openNotificationDrawer: jest.fn(),
openLateView: jest.fn(),
openSwingsView: jest.fn(),
setTabMode: jest.fn(),

...(values || {}),
})
Expand Down

0 comments on commit 0fde39e

Please sign in to comment.