Developer Hub
🔮 For applications
Guides & Tutorials
Tutorial: build your dApp
Step 5: Get and Display Game Info

Get and Display Game Info

Preparation: create helping components

GameInfo

Let's create a component to render game info, we'll use it later. Create src/components/GameInfo.tsx:

src/components/GameInfo.tsx
import dayjs from 'dayjs'
import { type GameQuery } from '@azuro-org/sdk'
 
 
type ParticipantLogoProps = {
  image?: string | null
  name: string
}
 
export function ParticipantLogo(props: ParticipantLogoProps) {
  const { image, name } = props
 
  return (
    <div className="flex flex-col items-center">
      <div className="flex items-center justify-center w-20 h-20 bg-white rounded-full">
        {
          Boolean(image) && (
            <img className="w-12 h-12" src={image!} alt="" />
          )
        }
      </div>
      <span className="max-w-[210px] mt-3 text-lg text-center">{name}</span>
    </div>
  )
}
 
type Props = {
  game: GameQuery['games'][0]
}
 
export function GameInfo(props: Props) {
  const { sport, league, participants, startsAt } = props.game
 
  return (
    <div className="flex flex-col items-center pt-6 pb-8 bg-zinc-50 rounded-[40px]">
      <div className="flex flex-col items-center text-md">
        <div>{sport.name}</div>
        <div className="mt-2 text-zinc-500">
          {league.country.name} &middot; {league.name}
        </div>
      </div>
      <div className="mt-5 grid grid-cols-[1fr_auto_1fr]">
        <ParticipantLogo {...participants[0]} />
        <div className="mx-5 pt-7 text-md text-zinc-500">
          {dayjs(+startsAt * 1000).format('DD MMM HH:mm')}
        </div>
        <ParticipantLogo {...participants[1]} />
      </div>
    </div>
  )
}

GameMarkets

This component will render all the markets for selected game. It uses previously created OutcomeButton.

Each market has a description, which can be used, for example, in tooltips. In this example we will just render them to show that it exists.

Create src/components/GameMarkets.tsx:

src/components/GameMarkets.tsx
'use client'
import type { GameMarkets, MarketOutcome } from '@azuro-org/sdk'
import { OutcomeButton } from '@/components'
 
 
type GameMarketsProps = {
  markets: GameMarkets
}
 
export function GameMarkets(props: GameMarketsProps) {
  const { markets } = props
 
  return (
    <div className="max-w-[600px] mx-auto mt-12 space-y-6">
      {
        markets.map(({ name, description, outcomeRows }) => (
          <div key={name} className="">
            <div className="mb-2 text-lg font-semibold">{name}</div>
            <div className="space-y-1">
              {
                outcomeRows.map((outcomes, index) => (
                  <div key={index} className="flex justify-between">
                    <div className="flex gap-2 w-full">
                      {
                        outcomes.map((outcome) => (
                          <OutcomeButton
                            key={outcome.selectionName}
                            outcome={outcome}
                          />
                        ))
                      }
                    </div>
                  </div>
                ))
              }
            </div>
          </div>
        ))
      }
    </div>
  )
}
⚠️

As always, don't forget to add all components export to src/components/index.ts.

Render game details

After creating helping components, let's use them together and render game details page.

Create folders for the page (src/app/event/[id]) and create page.tsx inside.

Here we'll use 2 hooks from Azuro SDK.

  • useGame - to fetch game data.
  • useGameStatus - to keep track of game status.
  • useGameMarkets - to fetch game markets and conditions. "Conditions" represents the data from the smart contracts with the same name. Each contract contains a set of outcomes, and there is no direct relationship between outcomes and markets in conditions. But it's mapped under the hood of SDK. If you are interested, you can check out the code (opens in a new tab) of helpers.
src/app/event/[id]/page.tsx
'use client'
import { useParams } from 'next/navigation'
import { useGame, useGameMarkets, type GameQuery, useGameStatus, GameStatus } from '@azuro-org/sdk'
import { GameInfo, GameMarkets } from '@/components'
 
 
type MarketsProps = {
  gameId: string
  gameStatus: GameStatus
}
 
const Markets: React.FC<MarketsProps> = ({ gameId, gameStatus }) => {
  const { loading, markets } = useGameMarkets({
    gameId,
    gameStatus,
  })
 
  if (loading) {
    return <div>Loading...</div>
  }
 
  if (!markets) {
    return null
  }
 
  return <GameMarkets markets={markets} />
}
 
type ContentProps = {
  game: GameQuery['games'][0]
  isGameInLive: boolean
}
 
const Content: React.FC<ContentProps> = ({ game, isGameInLive }) => {
  const { status: gameStatus } = useGameStatus({
    startsAt: +game.startsAt,
    graphStatus: game.status,
    isGameExistInLive: isGameInLive,
  })
 
  return (
    <>
      <GameInfo game={game} />
      <Markets
        gameId={game.gameId}
        gameStatus={gameStatus}
      />
    </>
  )
}
 
export default function Game() {
  const params = useParams()
 
  const { loading, game, isGameInLive } = useGame({
    gameId: params.id as string,
  })
 
  if (loading) {
    return <div>Loading...</div>
  }
 
  if (!game) {
    return (
      <div>Game info not found</div>
    )
  }
 
  return (
    <Content game={game} isGameInLive={isGameInLive} />
  )
}
 

Great job! Now we can click on game cards on events page and see the result:

Now we're ready to place first bet.

Learn more

In our tutorial we're building simple betting app. If you're ready to go deeper, learn things from SDK that we used in this section: