Tutorial
Get Game Details

Get Game Details

Fetch Game Data

Create a new file called useSportEvent.js in the hooks folder of your project. Copy and paste the following code into the file

hooks/useSportEvent.js
import { useRouter } from 'next/router'
import { gql, useQuery } from '@apollo/client'
 
const QUERY = `
  query Game($id: String!) {
    game(id: $id) {
      sport {
        name
      }
      league {
        name
        country {
          name
        }
      }
      participants {
        name
        image
      }
      startsAt
    }
  }
`
 
export default function useSportEvent() {
  const { query } = useRouter()
 
  return useQuery(gql`${QUERY}`, {
    variables: {
      id: query.id,
    },
  })
}

Get Markets and Outcomes

Because of technical limitations, it's not possible to directly access data on markets and outcomes (selections) from the protocol. Instead, the protocol uses entities called "conditions". To learn more about how conditions work, please refer to the documentation provided here.

Adjust the query with additional fields and use helpers to get markets

hooks/useSportEvent.js
import { useRouter } from 'next/router'
import { gql, useQuery } from '@apollo/client'
import { aggregateOutcomesByMarkets } from '@azuro-org/toolkit'
 
const QUERY = `
  query Game($id: String!) {
    game(id: $id) {
      sport {
        name
      }
      league {
        name
        country {
          name
        }
      }
      participants {
        name
        image
      }
      startsAt
      liquidityPool {
        address
      }
      conditions {
        conditionId
        status
        outcomes {
          id
          outcomeId
          odds
        }
        core {
          address
          type
        }
      }
    }
  }
`
 
export default function useSportEvent() {
  const { query } = useRouter()
 
  const { loading, data } = useQuery(gql`${QUERY}`, {
    variables: {
      id: query.id,
    },
  })
 
  let game
  let markets
 
  if (data?.game) {
    const { sport, league, participants, startsAt, liquidityPool, conditions } = data.game
 
    game = { sport, league, participants, startsAt }
 
    markets = aggregateOutcomesByMarkets({
      lpAddress: liquidityPool.address,
      conditions,
    })
  }
 
  return {
    loading,
    game,
    markets,
  }
}

"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. The aggregateOutcomesByMarkets helper uses a complex logic to map outcomes to their respective markets. If you are interested, you can check out the code (opens in a new tab).

Render Game Info UI

Create pages/games/[id].js file with the following content

pages/games/[id].js
import dayjs from 'dayjs'
import useSportEvent from '@/hooks/useSportEvent'
 
const ParticipantLogo = ({ image, name }) => (
  <div className="flex flex-col items-center">
    <div className="flex items-center justify-center w-20 h-20 border border-gray-300 rounded-full">
      <img className="w-12 h-12" src={image} alt={name} />
    </div>
    <span className="max-w-[210px] mt-3 text-lg text-center">{name}</span>
  </div>
)
 
const GameInfo = ({ sport, league, participants, startsAt }) => (
  <div className="flex flex-col items-center pt-6 pb-8 border border-gray-300 rounded-lg">
    <div className="flex flex-col items-center text-md">
      <div>{sport.name}</div>
      <div className="mt-2 text-gray-500">
        {league.country.name} &middot; {league.name}
      </div>
    </div>
    <div className="mt-5 grid lg:grid-cols-[1fr_auto_1fr]">
      <ParticipantLogo {...participants[0]} />
      <div className="mx-5 pt-7 text-md text-gray-500">
        {dayjs(startsAt * 1000).format('DD MMM HH:mm')}
      </div>
      <ParticipantLogo {...participants[1]} />
    </div>
  </div>
)
 
export default function Game() {
  const { loading, game } = useSportEvent()
 
  if (loading) {
    return <div>Loading...</div>
  }
 
  return (
    <main>
      <GameInfo {...game} />
    </main>
  )
}

Render Markets in UI

pages/games/[id].js
...
 
const Markets = ({ markets }) => (
  <div className="max-w-[600px] mx-auto mt-12 space-y-6">
    {
      markets.map(({ marketName, outcomes: row }) => (
        <div key={marketName} className="">
          <div className="mb-2 font-semibold">{marketName}</div>
          <div className="space-y-1">
            {
              row.map((outcomes, index) => (
                <div key={index} className="flex justify-between">
                  <div className="flex gap-1 w-full">
                    {
                      outcomes.map((outcome) => (
                        <div
                          key={outcome.selectionName}
                          className="flex justify-between py-2 px-3 bg-gray-200 rounded-md cursor-pointer hover:bg-gray-300 transition"
                          style={{ width: `calc(100% / ${outcomes.length})` }}
                        >
                          <span className="text-gray-500">{outcome.selectionName}</span>
                          <span className="font-medium">{parseFloat(outcome.odds).toFixed(2)}</span>
                        </div>
                      ))
                    }
                  </div>
                </div>
              ))
            }
          </div>
        </div>
      ))
    }
  </div>
)
 
export default function Game() {
  const { loading, game, markets } = useSportEvent()
 
  if (loading) {
    return <div>Loading...</div>
  }
 
  return (
    <main>
      <GameInfo {...game} />
      <Markets markets={markets} />
    </main>
  )
}

The result should look similar to