Skip to content

Commit

Permalink
feat: Populate detours list with channels (#2962)
Browse files Browse the repository at this point in the history
* feat: Populate detours list with channels instead of api fetch

* tests: update all tests to mock channels instead of fetch

* fix: require nearest intersection before saving detour/snapshot (#2973)

* don't try to save snapshot without nearestIntersection present

Co-authored-by: Brian Fauble <[email protected]>
Co-authored-by: Kayla Firestack <[email protected]>
  • Loading branch information
3 people authored Feb 28, 2025
1 parent 6ae2ab3 commit b175ae8
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 341 deletions.
49 changes: 36 additions & 13 deletions assets/src/components/detourListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useCallback, useState } from "react"
import React, { useContext, useState } from "react"
import { DetoursTable, DetourStatus } from "./detoursTable"
import userInTestGroup, { TestGroups } from "../userInTestGroup"
import { Button } from "react-bootstrap"
import { Button, Spinner } from "react-bootstrap"
import {
GlobeAmericas,
LockFill,
Expand All @@ -10,19 +10,38 @@ import {
SvgProps,
} from "../helpers/bsIcons"
import { DetourModal } from "./detours/detourModal"
import { fetchDetours } from "../api"
import { useApiCall } from "../hooks/useApiCall"
import { isOk } from "../util/result"
import { joinClasses } from "../helpers/dom"
import { useLoadDetour } from "../hooks/useLoadDetour"
import {
useActiveDetours,
useDraftDetours,
usePastDetours,
} from "../hooks/useDetours"
import { SocketContext } from "../contexts/socketContext"

export const DetourListPage = () => {
const [showDetourModal, setShowDetourModal] = useState(false)
const [detourId, setDetourId] = useState<number | undefined>()
const { result } = useApiCall({
apiCall: useCallback(async () => fetchDetours(), []),
})
const detours = result && isOk(result) && result.ok

// Wait for the detour channels to initialize
const { socket } = useContext(SocketContext)

const activeDetoursMap = useActiveDetours(socket)
const draftDetoursMap = useDraftDetours(socket)
const pastDetoursMap = usePastDetours(socket)

const activeDetours =
activeDetoursMap &&
Object.values(activeDetoursMap).sort(
(a, b) => b.activatedAt - a.activatedAt
)
const draftDetours =
draftDetoursMap &&
Object.values(draftDetoursMap).sort((a, b) => b.updatedAt - a.updatedAt)
const pastDetours =
pastDetoursMap &&
Object.values(pastDetoursMap).sort((a, b) => b.updatedAt - a.updatedAt)
// --- End of detour channel initialization

const detour = useLoadDetour(detourId)

Expand All @@ -48,7 +67,7 @@ export const DetourListPage = () => {
<span className="c-detour-list-page__button-text">Add detour</span>
</Button>
)}
{detours && (
{activeDetours && draftDetours && pastDetours ? (
<>
<Title
title="Active detours"
Expand All @@ -57,7 +76,7 @@ export const DetourListPage = () => {
classNames={["d-flex"]}
/>
<DetoursTable
data={detours.active}
data={activeDetours}
status={DetourStatus.Active}
onOpenDetour={onOpenDetour}
classNames={["mb-5"]}
Expand All @@ -71,7 +90,7 @@ export const DetourListPage = () => {
classNames={["u-hide-for-mobile", "d-md-flex"]}
/>
<DetoursTable
data={detours.draft}
data={draftDetours}
status={DetourStatus.Draft}
onOpenDetour={onOpenDetour}
classNames={["mb-5", "u-hide-for-mobile"]}
Expand All @@ -83,14 +102,18 @@ export const DetourListPage = () => {
classNames={["u-hide-for-mobile", "d-md-flex"]}
/>
<DetoursTable
data={detours.past}
data={pastDetours}
status={DetourStatus.Closed}
onOpenDetour={onOpenDetour}
classNames={["u-hide-for-mobile"]}
/>
</>
)}
</>
) : (
<div className="position-absolute inset-0 opacity-75 d-flex justify-content-center align-items-center">
<Spinner />
</div>
)}

{/* `detourId` exists before `stateOfDetourModal` does, so need this conditional
Expand Down
16 changes: 9 additions & 7 deletions assets/src/components/routeLadders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ const RouteLadders = ({
inTestGroup(TestGroups.DetoursOnLadder)
)

const skateDetoursByRouteName = Object.values(allActiveSkateDetours).reduce(
(acc: ByRouteId<DetoursMap>, cur: SimpleDetour) => {
acc[cur.route] = { ...acc[cur.route], [cur.id]: cur }
return acc
},
{}
)
const skateDetoursByRouteName = allActiveSkateDetours
? Object.values(allActiveSkateDetours).reduce(
(acc: ByRouteId<DetoursMap>, cur: SimpleDetour) => {
acc[cur.route] = { ...acc[cur.route], [cur.id]: cur }
return acc
},
{}
)
: {}

for (const routeId in alerts) {
if (alerts[routeId].length > 0) {
Expand Down
3 changes: 1 addition & 2 deletions assets/src/hooks/useDetour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ export const useDetour = (input: UseDetourInput) => {
const persistedSnapshot = actorRef.getPersistedSnapshot()
const serializedSnapshot = JSON.stringify(persistedSnapshot)
localStorage.setItem("snapshot", serializedSnapshot)

// check for no-save tag before
if (snap.hasTag("no-save")) {
if (snap.hasTag("no-save") || !snap.context.nearestIntersection) {
return
}

Expand Down
16 changes: 9 additions & 7 deletions assets/src/hooks/useDetours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export interface DetoursMap {
const subscribe = (
socket: Socket,
topic: string,
initializeChannel: React.Dispatch<React.SetStateAction<DetoursMap>>,
initializeChannel: React.Dispatch<
React.SetStateAction<DetoursMap | undefined>
>,
handleDrafted: ((data: SimpleDetour) => void) | undefined,
handleActivated: ((data: SimpleDetour) => void) | undefined,
handleDeactivated: ((data: SimpleDetour) => void) | undefined,
Expand Down Expand Up @@ -94,15 +96,15 @@ export const useActiveDetours = (
enable: boolean = true
) => {
const topic = "detours:active"
const [activeDetours, setActiveDetours] = useState<DetoursMap>({})
const [activeDetours, setActiveDetours] = useState<DetoursMap | undefined>()

const handleActivated = (data: SimpleDetour) => {
setActiveDetours((activeDetours) => ({ ...activeDetours, [data.id]: data }))
}

const handleDeactivated = (data: SimpleDetour) => {
setActiveDetours((activeDetours) => {
delete activeDetours[data.id]
if (activeDetours) delete activeDetours[data.id]
return activeDetours
})
}
Expand Down Expand Up @@ -139,7 +141,7 @@ export const useActiveDetours = (
// This is to refresh the Detours List page, past detours section
export const usePastDetours = (socket: Socket | undefined) => {
const topic = "detours:past"
const [pastDetours, setPastDetours] = useState<DetoursMap>({})
const [pastDetours, setPastDetours] = useState<DetoursMap | undefined>()

const handleDeactivated = (data: SimpleDetour) => {
setPastDetours((pastDetours) => ({ ...pastDetours, [data.id]: data }))
Expand Down Expand Up @@ -173,22 +175,22 @@ export const usePastDetours = (socket: Socket | undefined) => {
// This is to refresh the Detours List page, just the current user drafts
export const useDraftDetours = (socket: Socket | undefined) => {
const topic = "detours:draft:" + userUuid()
const [draftDetours, setDraftDetours] = useState<DetoursMap>({})
const [draftDetours, setDraftDetours] = useState<DetoursMap | undefined>()

const handleDrafted = (data: SimpleDetour) => {
setDraftDetours((draftDetours) => ({ ...draftDetours, [data.id]: data }))
}

const handleActivated = (data: SimpleDetour) => {
setDraftDetours((draftDetours) => {
delete draftDetours[data.id]
if (draftDetours) delete draftDetours[data.id]
return draftDetours
})
}

const handleDeleted = (detourId: number) => {
setDraftDetours((draftDetours) => {
delete draftDetours[detourId]
if (draftDetours) delete draftDetours[detourId]
return draftDetours
})
}
Expand Down
Loading

0 comments on commit b175ae8

Please sign in to comment.