Add real-time race events to your app

It’s time to update the frontend client to display the car’s position, telemetry and lap time in real-time. Leveraging subscriptions for specific events, you’ll display the position on a map and the telemetry and time data on a specific component.

1. Update your app code

Update the file src/pages/LiveRace.tsx with this content:

[ 🌟 ] src/pages/LiveRace.tsx

This page displays a list of Event using a component that fetch data leveraging the API category:

// fetch user info and list of events
  useEffect(() => {
    const prom = API.graphql({
      query: Queries.listEvents,
    }) as Promise<GraphQLResult<ListEventsQuery>>
    prom.then((result) => {
      // console.log(result)
      setEvents(
        (result.data?.listEvents?.items ?? []).map((item) => {
          return item as GEvent
        })
      )
    })

    return () => {}
  }, [])

Anytime a user selects an event, the page subscribes to race events via:

const sub = (
      API.graphql({
        query: onReceiveRaceEvent,
        variables: { eventId: selected.id },
      }) as unknown as Observable<
        SubscriptionValue<OnReceiveRaceEventSubscription>
      >
    ).subscribe({
      next: (resp) => {
        const raceEvent: RaceEvent = resp.value.data.onReceiveRaceEvent! as unknown as RaceEvent
        console.log(`the sub raceEvent >`, JSON.stringify(raceEvent, null, 2))
        let atBottom = false
        if (pane.current) {
          const window = pane.current.scrollHeight - pane.current.offsetHeight
          // console.log('before input text', pane.current.scrollTop, window)
          atBottom = pane.current.scrollTop === window
        }
        setRaceEvents((events) => updateRaceEvents(events, raceEvent))
        if(raceEvent.type == "_telemetry") {
          var eventToSet = raceEvent
          eventToSet.gear = raceEvent.gear != null ? raceEvent.gear : lastEvent?.gear
          eventToSet.speed = raceEvent.speed != null ? raceEvent.speed : lastEvent?.speed
          setLastEvent(eventToSet)
          setMarker({
            latitude: raceEvent.latitude,
            longitude: raceEvent.longitude
          })
        }
      },
    })

    return () => sub.unsubscribe()
  }, [selected])

Anytime a new race event is received, the page updates the list of race events and sets the last receied events to display the last available telemetry in the telemetry pane, as well as the last geolocation position in the map. For the map, the page uses the same component used previously in the Map page, but in this case the Marker is linked to the last received geolocation position event. This enable us to continuously show the car’s position on the track.

Let’s publish our changes to the cloud

amplify publish

2. Try out the race event

So far there are no race data for these events, but you can create a few more events in the Admin UI. Since we created a the raceSimulationScheduler lambda function, for every new Event created, you’ll get race data when the event date is reached.

Open the Admin UI, in the contents section let’s create a new Event. chat

In the create event form, fill all fields with some values. Please remember that the date is in UTC, so let’s use a value that allows you to test the race events within minutes.

chat

Now, let’s open the Step Function AWS console and check that a new workflow is running. chat

By selecting the running workflow, we can check the state. If the date of the event is still in the future, you’ll see the workflow is in the WaitForDueDate state. chat

Now, let’s reload your application if and head to the Live Race page. You should be able to select an event for the selection list. Select the event you’ve just created. As soon as the event starts, you’ll see telemetry events display in the page, such as current gear and current speed. chat

Also, you can scroll down and see in real-time the car position on the track. chat

Any time the car cross the finish line, a new lap time is triggered in real-time and the app populates the laptime list. chat

The full experience will look like the following. demo