Skip to content

Commit 809d4ed

Browse files
committed
fix: sort routes without start_time/end_time
- falls back to `create_time` when start_time/end_time are unavailable - refactor `<RouteHeader />` into its own file - hide `<RouteStatistics />` if there's no trip data closes commaai#60
1 parent 7e7dc85 commit 809d4ed

File tree

4 files changed

+55
-34
lines changed

4 files changed

+55
-34
lines changed

src/components/RouteCard.tsx

+8-28
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,13 @@
11
import { Suspense, type VoidComponent } from 'solid-js'
2-
import dayjs from 'dayjs'
32

4-
import Avatar from '~/components/material/Avatar'
5-
import Card, { CardContent, CardHeader } from '~/components/material/Card'
6-
import Icon from '~/components/material/Icon'
3+
import Card, { CardContent } from '~/components/material/Card'
4+
75
import RouteStaticMap from '~/components/RouteStaticMap'
86
import RouteStatistics from '~/components/RouteStatistics'
7+
import { RouteHeader } from './RouteHeader'
98

109
import type { RouteSegments } from '~/types'
1110

12-
const RouteHeader = (props: { route: RouteSegments }) => {
13-
const startTime = () => dayjs(props.route.start_time_utc_millis)
14-
const endTime = () => dayjs(props.route.end_time_utc_millis)
15-
16-
const headline = () => startTime().format('ddd, MMM D, YYYY')
17-
const subhead = () => `${startTime().format('h:mm A')} to ${endTime().format('h:mm A')}`
18-
19-
return (
20-
<CardHeader
21-
headline={headline()}
22-
subhead={subhead()}
23-
leading={
24-
<Avatar>
25-
<Icon>directions_car</Icon>
26-
</Avatar>
27-
}
28-
/>
29-
)
30-
}
31-
3211
interface RouteCardProps {
3312
route: RouteSegments
3413
}
@@ -45,10 +24,11 @@ const RouteCard: VoidComponent<RouteCardProps> = (props) => {
4524
<RouteStaticMap route={props.route} />
4625
</Suspense>
4726
</div>
48-
49-
<CardContent>
50-
<RouteStatistics route={props.route} />
51-
</CardContent>
27+
{!!props.route.end_time_utc_millis && (
28+
<CardContent>
29+
<RouteStatistics route={props.route} />
30+
</CardContent>
31+
)}
5232
</Card>
5333
)
5434
}

src/components/RouteHeader.tsx

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import dayjs from 'dayjs'
2+
3+
import Avatar from '~/components/material/Avatar'
4+
import { CardHeader } from '~/components/material/Card'
5+
import Icon from '~/components/material/Icon'
6+
7+
import type { RouteSegments } from '~/types'
8+
9+
export const RouteHeader = (props: { route: RouteSegments }) => {
10+
const startTime = () => dayjs(props.route.start_time_utc_millis ?? props.route.create_time * 1000)
11+
const endTime = () => dayjs(props.route.end_time_utc_millis)
12+
const headline = () => startTime().format('ddd, MMM D, YYYY')
13+
const subhead = () => {
14+
const startFormatted = startTime().format('h:mm A')
15+
return props.route.end_time_utc_millis ? `${startFormatted} to ${endTime().format('h:mm A')}` : startFormatted
16+
}
17+
18+
return (
19+
<CardHeader
20+
headline={headline()}
21+
subhead={subhead()}
22+
leading={
23+
<Avatar>
24+
<Icon>directions_car</Icon>
25+
</Avatar>
26+
}
27+
/>
28+
)
29+
}

src/pages/dashboard/components/RouteList.tsx

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-misused-promises */
22
import {
33
createEffect,
4+
createMemo,
45
createResource,
56
createSignal,
67
For,
@@ -29,7 +30,9 @@ const RouteList: VoidComponent<RouteListProps> = (props) => {
2930
const getKey = (previousPageData?: RouteSegments[]): string | undefined => {
3031
if (!previousPageData) return endpoint()
3132
if (previousPageData.length === 0) return undefined
32-
const lastSegmentEndTime = previousPageData.at(-1)!.end_time_utc_millis
33+
// if route has no end time, fall back to create_time
34+
const lastSegmentEndTime =
35+
previousPageData.at(-1)!.end_time_utc_millis ?? previousPageData.at(-1)!.create_time
3336
return `${endpoint()}&end=${lastSegmentEndTime - 1}`
3437
}
3538
const getPage = (page: number): Promise<RouteSegments[]> => {
@@ -38,7 +41,7 @@ const RouteList: VoidComponent<RouteListProps> = (props) => {
3841
pages[page] = new Promise(async (resolve) => {
3942
const previousPageData = page > 0 ? await getPage(page - 1) : undefined
4043
const key = getKey(previousPageData)
41-
resolve(key ? fetcher<RouteSegments[]>(key) : [])
44+
resolve(key ? fetcher<RouteSegments[]>(key) : [])
4245
})
4346
}
4447
return pages[page]
@@ -65,6 +68,15 @@ const RouteList: VoidComponent<RouteListProps> = (props) => {
6568
<For each={pageNumbers()}>
6669
{(i) => {
6770
const [routes] = createResource(() => i, getPage)
71+
const sortedRoutes = createMemo(() => {
72+
const currentRoutes = routes() ?? []
73+
// if route doesn't have start time, fall back to create_time
74+
return currentRoutes.sort((a, b) => {
75+
const startTimeA = a.start_time_utc_millis ?? a.create_time * 1000
76+
const startTimeB = b.start_time_utc_millis ?? b.create_time * 1000
77+
return startTimeB - startTimeA
78+
})
79+
})
6880
return (
6981
<Suspense
7082
fallback={
@@ -75,7 +87,7 @@ const RouteList: VoidComponent<RouteListProps> = (props) => {
7587
</>
7688
}
7789
>
78-
<For each={routes()}>
90+
<For each={sortedRoutes()}>
7991
{(route) => <RouteCard route={route} />}
8092
</For>
8193
</Suspense>

src/types.d.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export interface Route extends ApiResponseBase {
7979
procqcamera: number
8080
procqlog: number
8181
radar?: boolean
82-
start_time: string
82+
start_time?: string
8383
url: string
8484
user_id: string | null
8585
version?: string
@@ -92,9 +92,9 @@ export interface RouteShareSignature extends Record<string, string> {
9292
}
9393

9494
export interface RouteSegments extends Route {
95-
end_time_utc_millis: number
95+
end_time_utc_millis?: number
9696
is_preserved: boolean
9797
share_exp: RouteShareSignature['exp']
9898
share_sig: RouteShareSignature['sig']
99-
start_time_utc_millis: number
99+
start_time_utc_millis?: number
100100
}

0 commit comments

Comments
 (0)