Skip to content

Commit

Permalink
feat: add activated-at column to frontend detours list
Browse files Browse the repository at this point in the history
  • Loading branch information
firestack committed Jan 9, 2025
2 parents 8a4437d + 9412f6d commit 5693457
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 119 deletions.
66 changes: 58 additions & 8 deletions assets/src/components/detourListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { useCallback, useState } from "react"
import { DetoursTable, DetourStatus } from "./detoursTable"
import {
DetoursTable,
DetourStatus,
timestampLabelFromStatus,
} from "./detoursTable"
import userInTestGroup, { TestGroups } from "../userInTestGroup"
import { Button } from "react-bootstrap"
import { Button, Table } from "react-bootstrap"
import {
GlobeAmericas,
LockFill,
Expand All @@ -16,6 +20,9 @@ import { isErr, isOk } from "../util/result"
import { isValidSnapshot } from "../util/isValidSnapshot"
import { createDetourMachine } from "../models/createDetourMachine"
import { joinClasses } from "../helpers/dom"
import { RoutePill } from "./routePill"
import { timeAgoLabelForDates } from "../util/dateTime"
import { useCurrentTime } from "../hooks/useCurrentTime"

export const DetourListPage = () => {
const [showDetourModal, setShowDetourModal] = useState(false)
Expand Down Expand Up @@ -55,6 +62,8 @@ export const DetourListPage = () => {
setShowDetourModal(false)
}

const epochNow = useCurrentTime()

return (
<div className="c-detour-list-page h-100 overflow-y-auto p-0 p-md-4 bg-white">
{userInTestGroup(TestGroups.DetoursPilot) && (
Expand All @@ -75,12 +84,53 @@ export const DetourListPage = () => {
visibility="All Skate users"
classNames={["d-flex"]}
/>
<DetoursTable
data={detours.active}
status={DetourStatus.Active}
onOpenDetour={onOpenDetour}
classNames={["mb-5"]}
/>
<Table
hover={!!detours.active}
className={"mb-5 c-detours-table"}
variant={"active-detour"}
>
<thead className="u-hide-for-mobile">
<tr>
<th className="px-3 py-4">Route and direction</th>
<th className="px-3 py-4 u-hide-for-mobile">
Starting Intersection
</th>
<th className="px-3 py-4 u-hide-for-mobile">
{timestampLabelFromStatus(DetourStatus.Active)}
</th>
</tr>
</thead>
<tbody>
{detours.active
? detours.active.map((detour, index) => (
<tr
key={index}
onClick={() => onOpenDetour(detour.details.id)}
>
<td className="align-middle p-3">
<div className="d-flex">
<RoutePill routeName={detour.details.route} />
<div className="c-detours-table__route-info-text d-inline-block">
<div className="pb-1 fs-4 fw-semibold">
{detour.details.name}
</div>
<div className="c-detours-table__route-info-direction fs-6">
{detour.details.direction}
</div>
</div>
</div>
</td>
<td className="align-middle p-3 u-hide-for-mobile">
{detour.details.intersection}
</td>
<td className="align-middle p-3 u-hide-for-mobile">
{timeAgoLabelForDates(detour.activatedAt, epochNow)}
</td>
</tr>
))
: null}
</tbody>
</Table>
{userInTestGroup(TestGroups.DetoursPilot) && (
<>
<Title
Expand Down
2 changes: 1 addition & 1 deletion assets/src/hooks/useCurrentTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from "react"
import { now } from "../util/dateTime"
import useInterval from "./useInterval"

const useCurrentTime = (): Date => {
export const useCurrentTime = (): Date => {
const [currentTime, setCurrentTime] = useState(now())
useInterval(() => setCurrentTime(now()), 1000)
return currentTime
Expand Down
30 changes: 26 additions & 4 deletions assets/src/models/detoursList.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { array, Infer, nullable, number, string, type } from "superstruct"
import {
array,
coerce,
date,
Infer,
nullable,
number,
string,
type,
} from "superstruct"

export type DetourId = number
export interface SimpleDetour {
Expand All @@ -10,6 +19,11 @@ export interface SimpleDetour {
updatedAt: number
}

export interface ActivatedDetour {
activatedAt: Date
details: SimpleDetour
}

export const detourId = number()
export const SimpleDetourData = type({
id: detourId,
Expand All @@ -20,6 +34,11 @@ export const SimpleDetourData = type({
updated_at: number(),
})

export const ActivatedDetourData = type({
activated_at: coerce(date(), string(), (dateStr) => new Date(dateStr)),
details: SimpleDetourData,
})

export type SimpleDetourData = Infer<typeof SimpleDetourData>

export const simpleDetourFromData = (
Expand All @@ -34,13 +53,13 @@ export const simpleDetourFromData = (
})

export interface GroupedSimpleDetours {
active?: SimpleDetour[]
active?: ActivatedDetour[]
draft?: SimpleDetour[]
past?: SimpleDetour[]
}

export const GroupedDetoursData = type({
active: nullable(array(SimpleDetourData)),
active: nullable(array(ActivatedDetourData)),
draft: nullable(array(SimpleDetourData)),
past: nullable(array(SimpleDetourData)),
})
Expand All @@ -50,7 +69,10 @@ export type GroupedDetoursData = Infer<typeof GroupedDetoursData>
export const groupedDetoursFromData = (
groupedDetours: GroupedDetoursData
): GroupedSimpleDetours => ({
active: groupedDetours.active?.map((detour) => simpleDetourFromData(detour)),
active: groupedDetours.active?.map((detour) => ({
details: simpleDetourFromData(detour.details),
activatedAt: detour.activated_at,
})),
draft: groupedDetours.draft?.map((detour) => simpleDetourFromData(detour)),
past: groupedDetours.past?.map((detour) => simpleDetourFromData(detour)),
})
20 changes: 17 additions & 3 deletions assets/src/util/dateTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,27 @@ export const secondsAgoLabel = (
epochTime: number
): string => `${epochNowInSeconds - epochTime}s ago`

const second = 1000
const minute = second * 60
const hour = minute * 60

export const timeAgoLabel = (
epochNowInSeconds: number,
epochTime: number
): string => {
const duration = epochNowInSeconds - epochTime
const diffHours = Math.floor(duration / 3_600)
const diffMinutes = Math.floor((duration % 3_600) / 60)

return diffHours >= 1 ? `${diffHours} hours ago` : `${diffMinutes} min ago`
if (duration > 1 * hour) {
return `${Math.floor(duration / hour)} hours ago`
}

if (duration > 1 * minute) {
return `${Math.floor(duration / minute)} min ago`
}

return "Just now"
}

export const timeAgoLabelForDates = (start: Date, end: Date) => {
return timeAgoLabel(end.valueOf() / second, start.valueOf() / second)
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ exports[`DetourListPage renders detour list page for dispatchers 1`] = `
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
1 min ago
</td>
</tr>
<tr>
Expand Down Expand Up @@ -160,7 +160,7 @@ exports[`DetourListPage renders detour list page for dispatchers 1`] = `
<td
class="align-middle p-3 u-hide-for-mobile"
>
29 hours ago
1 min ago
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -349,7 +349,7 @@ exports[`DetourListPage renders detour list page for dispatchers 1`] = `
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
1 min ago
</td>
</tr>
<tr>
Expand Down Expand Up @@ -388,7 +388,7 @@ exports[`DetourListPage renders detour list page for dispatchers 1`] = `
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
1 min ago
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -492,7 +492,7 @@ exports[`DetourListPage renders limited detour list page for non-dispatchers 1`]
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
1 min ago
</td>
</tr>
<tr>
Expand Down Expand Up @@ -531,7 +531,7 @@ exports[`DetourListPage renders limited detour list page for non-dispatchers 1`]
<td
class="align-middle p-3 u-hide-for-mobile"
>
29 hours ago
1 min ago
</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
Just now
</td>
</tr>
<tr>
Expand Down Expand Up @@ -163,7 +163,7 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
Just now
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -352,7 +352,7 @@ exports[`Detours Page: Open a Detour renders detour details in an open drawer on
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
1 min ago
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -971,7 +971,7 @@ exports[`Detours Page: Open a Detour renders detour details modal to match mocke
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
Just now
</td>
</tr>
<tr>
Expand Down Expand Up @@ -1010,7 +1010,7 @@ exports[`Detours Page: Open a Detour renders detour details modal to match mocke
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
Just now
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -1199,7 +1199,7 @@ exports[`Detours Page: Open a Detour renders detour details modal to match mocke
<td
class="align-middle p-3 u-hide-for-mobile"
>
26 hours ago
1 min ago
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -1228,7 +1228,7 @@ exports[`Detours Page: Open a Detour renders detour details modal to match mocke
>
Last edited
</strong>
26 hours ago
1 min ago
</span>
<span
class="l-diversion-page__header-details"
Expand Down
60 changes: 36 additions & 24 deletions assets/tests/components/detours/detourListPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,26 @@ describe("DetourListPage", () => {
Ok({
active: [
{
id: 1,
route: "1",
direction: "Inbound",
name: "Headsign A",
intersection: "Street A & Avenue B",
updatedAt: 1724866392,
details: {
id: 1,
route: "1",
direction: "Inbound",
name: "Headsign A",
intersection: "Street A & Avenue B",
updatedAt: 1724866392,
},
activatedAt: new Date(1724866392000),
},
{
id: 8,
route: "2",
direction: "Outbound",
name: "Headsign B",
intersection: "Street C & Avenue D",
updatedAt: 1724856392,
details: {
id: 8,
route: "2",
direction: "Outbound",
name: "Headsign B",
intersection: "Street C & Avenue D",
updatedAt: 1724856392,
},
activatedAt: new Date(1724856392000),
},
],
draft: undefined,
Expand Down Expand Up @@ -93,20 +99,26 @@ describe("DetourListPage", () => {
Ok({
active: [
{
id: 1,
route: "1",
direction: "Inbound",
name: "Headsign A",
intersection: "Street A & Avenue B",
updatedAt: 1724866392,
details: {
id: 1,
route: "1",
direction: "Inbound",
name: "Headsign A",
intersection: "Street A & Avenue B",
updatedAt: 1724866392,
},
activatedAt: new Date(1724866392000),
},
{
id: 8,
route: "2",
direction: "Outbound",
name: "Headsign B",
intersection: "Street C & Avenue D",
updatedAt: 1724856392,
details: {
id: 8,
route: "2",
direction: "Outbound",
name: "Headsign B",
intersection: "Street C & Avenue D",
updatedAt: 1724856392,
},
activatedAt: new Date(1724856392000),
},
],
draft: undefined,
Expand Down
Loading

0 comments on commit 5693457

Please sign in to comment.