-
+ {todayIsHalloween() ? (
+
+ ) : (
+
+ )}
-
@@ -69,4 +74,20 @@ const TopNav = (): JSX.Element => {
)
}
+export const HalloweenIcon = (props: BsIcon.SvgProps) => (
+
+)
+
export default TopNav
diff --git a/assets/src/components/vehicleIcon.tsx b/assets/src/components/vehicleIcon.tsx
index 913715b09..58c566c75 100644
--- a/assets/src/components/vehicleIcon.tsx
+++ b/assets/src/components/vehicleIcon.tsx
@@ -2,7 +2,11 @@ import React, { ReactElement } from "react"
import Tippy from "@tippyjs/react"
import "tippy.js/dist/tippy.css"
import { joinClasses } from "../helpers/dom"
-import { DrawnStatus, statusClasses } from "../models/vehicleStatus"
+import {
+ DrawnStatus,
+ OnTimeStatus,
+ statusClasses,
+} from "../models/vehicleStatus"
import { AlertIconStyle, IconAlertCircleSvgNode } from "./iconAlertCircle"
import { runIdToLabel } from "../helpers/vehicleLabel"
import { isGhost } from "../models/vehicle"
@@ -10,6 +14,7 @@ import { Ghost, RunId, Vehicle, VehicleInScheduledService } from "../realtime"
import { BlockId, ViaVariant } from "../schedule.d"
import { scheduleAdherenceLabelString } from "./propertiesPanel/header"
import { UserSettings } from "../userSettings"
+import { todayIsHalloween } from "../helpers/date"
import {
directionOnLadder,
getLadderDirectionForRoute,
@@ -279,6 +284,8 @@ export const VehicleIconSvgNode = React.memo(
) : null}
{status === "ghost" ? (
+ ) : isBat(status) ? (
+
) : (
)}
@@ -320,6 +327,32 @@ const Triangle = React.memo(
}
)
+const isBat = (
+ status: OnTimeStatus | "off-course" | "ghost" | "plain" | "logged-out"
+) => status === "off-course" && todayIsHalloween()
+
+const Bat = ({ size }: { size: Size }) => {
+ const scale = scaleBatForSize(size)
+ return (
+
+ )
+}
+
+const scaleBatForSize = (size: Size): number => {
+ switch (size) {
+ case Size.Small:
+ return 0.38
+ case Size.Medium:
+ return 0.5
+ case Size.Large:
+ return 1
+ }
+}
+
const GhostIcon = React.memo(
({ size, variant }: { size: Size; variant?: string }) => {
// No orientation argument, because the ghost icon is always right side up.
@@ -437,18 +470,23 @@ const Variant = React.memo(
status: DrawnStatus
}) => {
const scale = scaleForSize(size)
+ const bat = isBat(status)
+ const isSideways =
+ orientation === Orientation.Left || orientation === Orientation.Right
// space between the triangle base and the variant letter
let margin = 0
switch (size) {
case Size.Small:
- margin = status === "ghost" ? 4 : 2
+ margin = status === "ghost" || bat ? 4 : 2
+ if (bat && isSideways) margin++
break
case Size.Medium:
- margin = status === "ghost" ? 8 : 4
+ margin = status === "ghost" || bat ? 8 : 4
break
case Size.Large:
- margin = status === "ghost" ? 12 : 6
+ margin = status === "ghost" || bat ? 12 : 6
+ if (bat && isSideways) margin += 2
break
}
diff --git a/assets/src/helpers/date.ts b/assets/src/helpers/date.ts
new file mode 100644
index 000000000..9118a303e
--- /dev/null
+++ b/assets/src/helpers/date.ts
@@ -0,0 +1,2 @@
+export const todayIsHalloween = (today: Date = new Date()): boolean =>
+ today.getMonth() === 9 && today.getDate() === 31
diff --git a/assets/src/hooks/useSwings.ts b/assets/src/hooks/useSwings.ts
index d5cdf9beb..25c3f1712 100644
--- a/assets/src/hooks/useSwings.ts
+++ b/assets/src/hooks/useSwings.ts
@@ -12,9 +12,9 @@ const useSwings = (): Swing[] | null => {
allOpenRouteIds(routeTabs)
)
- const newRouteIds = allOpenRouteIds(routeTabs)
+ const newRouteIds = routeTabs.find((v) => v.isCurrentTab)?.selectedRouteIds
- if (!equalByElements(routeIds, newRouteIds)) {
+ if (newRouteIds && !equalByElements(routeIds, newRouteIds)) {
setRouteIds(newRouteIds)
}
diff --git a/assets/src/models/createDetourMachine.ts b/assets/src/models/createDetourMachine.ts
index f420dc4ce..82335462c 100644
--- a/assets/src/models/createDetourMachine.ts
+++ b/assets/src/models/createDetourMachine.ts
@@ -10,6 +10,7 @@ import {
fetchRoutePatterns,
} from "../api"
import { DetourShape, FinishedDetour } from "./detour"
+import { fullStoryEvent } from "../helpers/fullStory"
export const createDetourMachine = setup({
types: {
@@ -351,12 +352,17 @@ export const createDetourMachine = setup({
on: {
"detour.edit.place-waypoint-on-route": {
target: "Place Waypoint",
- actions: {
- type: "detour.add-start-point",
- params: ({ event: { location } }) => ({
- location,
- }),
- },
+ actions: [
+ {
+ type: "detour.add-start-point",
+ params: ({ event: { location } }) => ({
+ location,
+ }),
+ },
+ () => {
+ fullStoryEvent("Placed Detour Start Point", {})
+ },
+ ],
},
},
},
@@ -397,21 +403,31 @@ export const createDetourMachine = setup({
"detour.edit.place-waypoint": {
target: "Place Waypoint",
reenter: true,
- actions: {
- type: "detour.add-waypoint",
- params: ({ event: { location } }) => ({
- location,
- }),
- },
+ actions: [
+ {
+ type: "detour.add-waypoint",
+ params: ({ event: { location } }) => ({
+ location,
+ }),
+ },
+ () => {
+ fullStoryEvent("Placed Detour Way-Point", {})
+ },
+ ],
},
"detour.edit.place-waypoint-on-route": {
target: "Finished Drawing",
- actions: {
- type: "detour.add-end-point",
- params: ({ event: { location } }) => ({
- location,
- }),
- },
+ actions: [
+ {
+ type: "detour.add-end-point",
+ params: ({ event: { location } }) => ({
+ location,
+ }),
+ },
+ () => {
+ fullStoryEvent("Placed Detour End Point", {})
+ },
+ ],
},
"detour.edit.undo": [
{
diff --git a/assets/tests/components/app.test.tsx b/assets/tests/components/app.test.tsx
index 42f33a9d2..9635dde35 100644
--- a/assets/tests/components/app.test.tsx
+++ b/assets/tests/components/app.test.tsx
@@ -27,6 +27,11 @@ import { viewFactory } from "../factories/pagePanelStateFactory"
import userEvent from "@testing-library/user-event"
import { mockUsePanelState } from "../testHelpers/usePanelStateMocks"
+// Avoid Halloween
+jest
+ .useFakeTimers({ doNotFake: ["setTimeout"] })
+ .setSystemTime(new Date("2018-08-15T17:41:21.000Z"))
+
jest.mock("../../src/hooks/useDataStatus", () => ({
__esModule: true,
default: jest.fn(() => "good"),
diff --git a/assets/tests/components/appStateWrapper.test.tsx b/assets/tests/components/appStateWrapper.test.tsx
index 8138e03a8..f0e3004b2 100644
--- a/assets/tests/components/appStateWrapper.test.tsx
+++ b/assets/tests/components/appStateWrapper.test.tsx
@@ -3,6 +3,11 @@ import React from "react"
import { render } from "@testing-library/react"
import AppStateWrapper from "../../src/components/appStateWrapper"
+// Avoid Halloween
+jest
+ .useFakeTimers({ doNotFake: ["setTimeout"] })
+ .setSystemTime(new Date("2024-08-29T20:00:00"))
+
jest.mock("userTestGroups", () => ({
__esModule: true,
default: jest.fn(() => []),
diff --git a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap
index fb6fc697d..23b8132a9 100644
--- a/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap
+++ b/assets/tests/components/detours/__snapshots__/detoursListPage.openDetour.test.tsx.snap
@@ -367,6 +367,7 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on
>