Skip to content

Commit

Permalink
add IndyCar and refactor session mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
appsbytom committed Aug 8, 2023
1 parent 15995a2 commit 40a713e
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 39 deletions.
27 changes: 18 additions & 9 deletions lib/motorsportstats/motorsportstats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ import Event from '@/types/event'
import Session from '@/types/session'
import axios from 'axios'
import dayjs from 'dayjs'
import { CalendarResponse, EventResponse, ProcessSessions, Season, SeasonsResponse, SessionMap, SessionResponse } from './types'
import {
CalendarResponse,
EventResponse,
GetSessionType,
ProcessSessions,
Season,
SeasonsResponse,
SessionResponse
} from './types'

const CLIENT = axios.create({
baseURL: 'https://api.motorsportstats.com/widgets/1.0.0',
Expand All @@ -13,7 +21,8 @@ const CLIENT = axios.create({
const SERIES_MAP: { [key in MotorsportStatsSeries]: string } = {
[Series.FE]: '7415d1ab-c31d-49dd-9143-1e7e33bff889',
[Series.BTCC]: 'ee00e922-a28b-4a8e-ae84-597af14ed931',
[Series.ExtremeE]: 'a4373eb9-8102-48fd-a11f-215a2ce662c1'
[Series.ExtremeE]: 'a4373eb9-8102-48fd-a11f-215a2ce662c1',
[Series.IndyCar]: '220b82cb-7fdb-46df-b8f8-d180118aa605'
}

const getCurrentSeason = async (series: MotorsportStatsSeries): Promise<Season> => {
Expand All @@ -24,43 +33,43 @@ const getCurrentSeason = async (series: MotorsportStatsSeries): Promise<Season>

const isoFromUnix = (unix: number) => dayjs.unix(unix).toISOString()

const toEvent = (event: EventResponse, series: MotorsportStatsSeries, sessionMap: SessionMap, processSessions: ProcessSessions): Event => {
const toEvent = (event: EventResponse, series: MotorsportStatsSeries, getSessionType: GetSessionType, processSessions: ProcessSessions): Event => {
const hasSessions = event.sessions.length > 0
return {
id: event.uuid,
name: event.name.replace('/', ' '),
sessions: hasSessions ? getSessions(processSessions(event.sessions), sessionMap) : [],
sessions: hasSessions ? getSessions(processSessions(event.sessions), getSessionType) : [],
provisional: !hasSessions,
series,
raceDate: isoFromUnix(event.endTimeUtc)
}
}

export const getSeriesEvents = async (series: MotorsportStatsSeries, sessionMap: SessionMap, processSessions: ProcessSessions = sessions => sessions, processEvent: (event: EventResponse) => EventResponse | EventResponse[] = event => event): Promise<Event[]> => {
export const getSeriesEvents = async (series: MotorsportStatsSeries, getSessionType: GetSessionType, processSessions: ProcessSessions = sessions => sessions, processEvent: (event: EventResponse) => EventResponse | EventResponse[] = event => event): Promise<Event[]> => {
const season = await getCurrentSeason(series)
const { data } = await CLIENT.get<CalendarResponse>(`/seasons/${season.uuid}/calendar`)

return data.events.reduce<Event[]>((acc, event) => {
if (!event.status) {
const processed = processEvent(event);
if (Array.isArray(processed)) {
acc.push(...processed.map(value => toEvent(value, series, sessionMap, processSessions)))
acc.push(...processed.map(value => toEvent(value, series, getSessionType, processSessions)))
} else {
acc.push(toEvent(processed, series, sessionMap, processSessions))
acc.push(toEvent(processed, series, getSessionType, processSessions))
}
}

return acc;
}, [])
}

const getSessions = (sessions: SessionResponse[], sessionMap: SessionMap): Session[] => {
const getSessions = (sessions: SessionResponse[], getSessionType: GetSessionType): Session[] => {
return sessions
.sort((a, b) => a.startTimeUtc - b.startTimeUtc)
.map(session => ({
id: session.uuid,
name: session.name,
type: sessionMap[session.shortCode],
type: getSessionType(session.shortCode),
unconfirmed: false,
startTime: isoFromUnix(session.startTimeUtc),
endTime: isoFromUnix(session.endTimeUtc)
Expand Down
2 changes: 1 addition & 1 deletion lib/motorsportstats/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export type Season = {
status: string
}

export type SessionMap = { [key: string]: Type }
export type GetSessionType = (sessionCode: string) => Type | undefined

export type ProcessSessions = (sessions: SessionResponse[]) => SessionResponse[]
9 changes: 7 additions & 2 deletions series/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ export enum Series {
F3 = 'f3',
FE = 'fe',
BTCC = 'btcc',
ExtremeE = 'extreme-e'
ExtremeE = 'extreme-e',
IndyCar = 'indycar'
}

export type MotorsportStatsSeries = Series.FE | Series.BTCC | Series.ExtremeE
export type MotorsportStatsSeries = Series.FE | Series.BTCC | Series.ExtremeE | Series.IndyCar

export type SeriesMap<T> = { [key in Series]: T }

Expand Down Expand Up @@ -40,6 +41,10 @@ const SERIES_CONFIG: SeriesMap<SeriesInfo> = {
[Series.ExtremeE]: {
name: 'Extreme E',
colours: 'bg-[#02FD9C]'
},
[Series.IndyCar]: {
name: 'IndyCar',
colours: 'bg-[#0075C9]'
}
}

Expand Down
4 changes: 3 additions & 1 deletion series/fetcher-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import f1 from './fetchers/f1/f1'
import f2 from './fetchers/f2f3/f2'
import f3 from './fetchers/f2f3/f3'
import fe from './fetchers/fe'
import indycar from './fetchers/indycar'

const SERIES_FETCHER_CONFIG: SeriesMap<() => Promise<Event[]>> = {
[Series.F1]: f1,
[Series.F2]: f2,
[Series.F3]: f3,
[Series.FE]: fe,
[Series.BTCC]: btcc,
[Series.ExtremeE]: extremeE
[Series.ExtremeE]: extremeE,
[Series.IndyCar]: indycar
}

export const getAllEvents = async (): Promise<Event[]> => {
Expand Down
13 changes: 6 additions & 7 deletions series/fetchers/btcc.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { getSeriesEvents } from '@/lib/motorsportstats/motorsportstats'
import { GetSessionType } from '@/lib/motorsportstats/types'
import { Series } from '@/series/config'
import Event from '@/types/event'
import { Type } from '@/types/session'

const SESSION_TYPE_MAP = {
P1: Type.Practice,
P2: Type.Practice,
Q1: Type.Qualifying,
Q2: Type.Qualifying,
Race: Type.Race
const getSessionType: GetSessionType = (sessionCode) => {
if (/^P\d*$/.test(sessionCode)) return Type.Practice
if (/^Q\d*$/.test(sessionCode)) return Type.Qualifying
if (sessionCode === 'Race') return Type.Race
}

export default async (): Promise<Event[]> => getSeriesEvents(Series.BTCC, SESSION_TYPE_MAP)
export default async (): Promise<Event[]> => getSeriesEvents(Series.BTCC, getSessionType)
14 changes: 6 additions & 8 deletions series/fetchers/extreme-e.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { getSeriesEvents } from '@/lib/motorsportstats/motorsportstats'
import { GetSessionType } from '@/lib/motorsportstats/types'
import { Series } from '@/series/config'
import { Type } from '@/types/session'

const SESSION_TYPE_MAP = {
FP1: Type.Practice,
FP2: Type.Practice,
QH1: Type.Qualifying,
QH2: Type.Qualifying,
RR: Type.Race,
Race: Type.Race
const getSessionType: GetSessionType = (sessionCode) => {
if (/^FP\d*$/.test(sessionCode)) return Type.Practice
if (/^QH\d*$/.test(sessionCode)) return Type.Qualifying
if (sessionCode === 'Race' || sessionCode === 'RR') return Type.Race
}

export default () => getSeriesEvents(Series.ExtremeE, SESSION_TYPE_MAP, sessions => sessions, (event) => {
export default () => getSeriesEvents(Series.ExtremeE, getSessionType, sessions => sessions, (event) => {
const sessions = event.sessions.filter(session => session.name !== 'Race')
if (sessions.filter(session => session.shortCode === 'Race').length > 1) {
const firstRaceIndex = sessions.findIndex(session => session.shortCode === 'Race') + 1
Expand Down
16 changes: 7 additions & 9 deletions series/fetchers/fe.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import { getSeriesEvents } from '@/lib/motorsportstats/motorsportstats'
import { SessionResponse } from '@/lib/motorsportstats/types'
import { GetSessionType, ProcessSessions } from '@/lib/motorsportstats/types'
import { Series } from '@/series/config'
import Event from '@/types/event'
import { Type } from '@/types/session'
import partition from '@/utils/partition'

const SESSION_TYPE_MAP = {
P1: Type.Practice,
P2: Type.Practice,
P3: Type.Practice,
Q: Type.Qualifying,
Race: Type.Race
const getSessionType: GetSessionType = (sessionCode) => {
if (/^P\d*$/.test(sessionCode)) return Type.Practice
if (sessionCode === 'Q') return Type.Qualifying
if (sessionCode === 'Race') return Type.Race
}

const groupQualifying = (sessions: SessionResponse[]): SessionResponse[] => {
const groupQualifying: ProcessSessions = (sessions) => {
const [{ 0: firstQualifying, length, [length - 1]: lastQualifying }, otherSessions] = partition(sessions, session => session.shortCode.startsWith('Q'))

return otherSessions.concat({ uuid: 'q', name: 'Qualifying', shortCode: 'Q', startTimeUtc: firstQualifying.startTimeUtc, endTimeUtc: lastQualifying.endTimeUtc })
}

export default async (): Promise<Event[]> => getSeriesEvents(Series.FE, SESSION_TYPE_MAP, groupQualifying)
export default async (): Promise<Event[]> => getSeriesEvents(Series.FE, getSessionType, groupQualifying)
21 changes: 21 additions & 0 deletions series/fetchers/indycar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getSeriesEvents } from '@/lib/motorsportstats/motorsportstats'
import { GetSessionType, ProcessSessions } from '@/lib/motorsportstats/types'
import { Type } from '@/types/session'
import partition from '@/utils/partition'
import { Series } from '../config'

const getSessionType: GetSessionType = (sessionCode) => {
if (/^P\d*$/.test(sessionCode) || sessionCode === 'FPR' || sessionCode === 'WU') {
return Type.Practice
}
if (sessionCode === 'Q') return Type.Qualifying
if (sessionCode === 'Race') return Type.Race
}

const groupQualifying: ProcessSessions = (sessions) => {
const [{ 0: firstQualifying, length, [length - 1]: lastQualifying }, otherSessions] = partition(sessions, session => /^Q\d*$/.test(session.shortCode))

return otherSessions.concat({ uuid: 'q', name: 'Qualifying', shortCode: 'Q', startTimeUtc: firstQualifying.startTimeUtc, endTimeUtc: lastQualifying.endTimeUtc })
}

export default () => getSeriesEvents(Series.IndyCar, getSessionType, groupQualifying)
2 changes: 1 addition & 1 deletion types/session.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
type Session = {
id: number | string
name: string
type: Type
type?: Type
unconfirmed: boolean
startTime: string
endTime: string
Expand Down
3 changes: 2 additions & 1 deletion types/week.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Series } from '@/series/config'
import Event from './event'
import Session from './session'
import Session, { Type } from './session'

type Week = {
date: string
Expand All @@ -16,6 +16,7 @@ type Day = {

export type GroupedSession = Session & {
series: Series
type: Type
eventName: string
}

Expand Down

1 comment on commit 40a713e

@vercel
Copy link

@vercel vercel bot commented on 40a713e Aug 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

raceweek – ./

raceweek-appsbytom.vercel.app
raceweek-git-main-appsbytom.vercel.app
raceweek.vercel.app

Please sign in to comment.