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
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
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
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} · {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
...
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
