<div class="match-score" data-behaviour='match-score-live' data-match-id="asakmolx3ewk6zqs42cdrb97u">
<div class="match-score__goalscorers-left">
<div class="goal-scorers " data-behaviour="home-team">
<div class="goal-scorers__group player-scored">
<ul>
<li>
<span class="scorer-firstname">Kane</span>Kane
<span class="goal-time">(4′)</span>
<span class="goal-time">(63′)</span>
</li>
<li>
<span class="scorer-firstname">Rashford</span>Rashford
<span class="goal-time">(23′ PEN)</span>
</li>
</ul>
</div>
<div class="goal-scorers__group player-sent-off">
<ul>
<li>
<span class="scorer-firstname">Mings</span>Mings
<span class="goal-time">(76′)</span>
</li>
</ul>
</div>
<div class="goal-scorers__group missed-a-penalty">
<ul>
<li>
<span class="scorer-firstname">Mings</span>Mings
<span class="goal-time">(41′ MISSED PEN)</span>
</li>
</ul>
</div>
</div>
</div>
<div class="match-score__scoreline">
<div class="scoreline">
<div class="scoreline__live">
<div class="circle-wrapper">
<span class="pulsating-circle"></span>
</div>
<span>live </span>
<span class="minutes" data-behaviour="match-length">64</span>
</div>
<div class="scoreline__location"><span>Sat 31 March, 3pm</span> <span>Wembley stadium, England</span></div>
<div class="scoreline__results">
<div class="scoreline__team-crests">
<img src="/assets/example-content/team-badge-eng.png" alt="England" />
</div>
<div class="scoreline__team-goals" data-behaviour="team-goals-scored">
<div class="scoreline__team-goals--scored scoreline__team-goals--live-score">
<span>4</span>
<span>2</span>
</div>
<div class="scoreline__team-goals--time">
<span class="scoreline__team-goals--ht">HT: 2-2</span>
<span class="scoreline__team-goals--ft">FT: 2-3</span>
</div>
</div>
<div class="scoreline__team-crests">
<img src="/assets/example-content/team-badge-isl.png" alt="Iceland" />
</div>
</div>
</div>
</div>
<div class="match-score__goalscorers-right">
<div class="goal-scorers goal-scorers--invert " data-behaviour="away-team">
<div class="goal-scorers__group player-scored">
<ul>
<li>
<span class="scorer-firstname">Sterling</span>Sterling
<span class="goal-time">(19′)</span>
</li>
<li>
<span class="scorer-firstname">Sterling</span>Sterling
<span class="goal-time">(46′)</span>
</li>
</ul>
</div>
<div class="goal-scorers__group player-sent-off">
<ul>
<li>
<span class="scorer-firstname">Sterling</span>Sterling
<span class="goal-time">(65′)</span>
</li>
<li class="yellowcard">
<span class="scorer-firstname">Sterling</span>Sterling
<span class="goal-time">(64′)</span>
</li>
<li class="yellowredcard">
<span class="scorer-firstname">Sterling</span>Sterling
<span class="goal-time">(64′)</span>
</li>
</ul>
</div>
</div>
</div>
</div>
No notes defined.
{
"liveScore": true,
"ftScoreVisible": true,
"matchId": "asakmolx3ewk6zqs42cdrb97u"
}
/* eslint-disable prettier/prettier */
/* eslint-disable no-param-reassign */
const headers = {
'Ocp-Apim-Subscription-Key': '8279c7fab35f432daf1a0bd395a9ae48',
};
const POLL_TIMING = 1000 * 60; // per 1min.
// utility to check empty object
const isEmptyObject = obj => Object.keys(obj).length === 0 && obj.constructor === Object;
// utility to group by for provided `key` on `array`
const groupBy = (array, key) => {
return array.reduce((objectsByKeyValue, obj) => {
const value = obj[key];
objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
return objectsByKeyValue;
}, {});
};
async function fetchLiveScore(matchId) {
// replace url with `/livescore/` in development to see results
const url = `${window.location.origin}/LiveMatch/LiveMatchDetails?matchid=${matchId}`;
// eslint-disable-next-line compat/compat
const response = await fetch(url, {
headers,
});
return response.json();
};
// will update home team scores (left section)
const renderGoalScorerHomeTeam = ({
goal,
missedPen,
card
}, { home }) => {
let markup = '';
const homeGoals = groupBy(goal.filter(g => g.contestantId === home), 'scorerId');
const homeCards = groupBy(card.filter(c => c.contestantId === home), 'playerId');
const homeMissedPens = groupBy(missedPen.filter(p => p.contestantId === home && p.type === 'PM'), 'playerId');
if (!isEmptyObject(homeGoals)) {
markup += `<div class="goal-scorers__group player-scored">
<ul>
${Object.keys(homeGoals)
.map(scorerId => {
return `
<li>
<span class="scorer-firstname"></span>${homeGoals[scorerId][0].scorerName}
<span class="goal-time">
${homeGoals[scorerId].map(hgScorer => {
const type = hgScorer.type !== 'G' ? hgScorer.type : '';
return `(${hgScorer.timeMin}′${type})`;
}).join('\n')}
</span>
</li>`;
})
.join('\n')}
</ul>
</div>`;
}
if (!isEmptyObject(homeCards)) {
markup += `<div class="goal-scorers__group player-sent-off">
<ul>
${Object.keys(homeCards)
.map(playerId => {
return homeCards[playerId].map((hcPlayer, index) => {
let clsName;
if (index === 0 && homeCards[playerId][index].type === 'YC') {
clsName = 'yellowcard';
} else if (index === 1 && homeCards[playerId][index].type === 'YC') {
clsName = 'yellowredcard';
} else {
clsName = '';
}
return `
<li class="${clsName}">
<span class="scorer-firstname"></span>${homeCards[playerId][0].playerName}
<span class="goal-time">
(${hcPlayer.timeMin}′)
</span>
</li>`;
}).join('\n')
})
.join('\n')}
</ul>
</div>`;
}
if(!isEmptyObject(homeMissedPens)) {
markup += `<div class="goal-scorers__group missed-a-penalty">
<ul>
${Object.keys(homeMissedPens)
.map(playerId => {
return `<li>
<span class="scorer-firstname"></span>${homeMissedPens[playerId][0].playerName}
<span class="goal-time">
${homeMissedPens[playerId].map(player => {
return `(${player.timeMin}′ MISSED PEN)`;
}).join('\n')}
</span>
</li>`;
})
.join('\n')}
</ul>
</div>`;
}
return markup;
};
// will update away team scores (right section)
const renderGoalScorerAwayTeam = ({
goal,
missedPen,
card
}, { away }) => {
let markup = '';
const awayGoals = groupBy(goal.filter(g => g.contestantId === away), 'scorerId');
const awayCards = groupBy(card.filter(c => c.contestantId === away), 'playerId');
const awayMissedPens = groupBy(missedPen.filter(p => p.contestantId === away && p.type === 'PM'), 'playerId');
if (!isEmptyObject(awayGoals)) {
markup += `<div class="goal-scorers__group player-scored">
<ul>
${Object.keys(awayGoals)
.map(scorerId => {
return `
<li>
<span class="scorer-firstname"></span>${awayGoals[scorerId][0].scorerName}
<span class="goal-time">
${awayGoals[scorerId].map(hgScorer => {
const type = hgScorer.type !== 'G' ? hgScorer.type : '';
return `(${hgScorer.timeMin}′${type})`
}).join('\n')}
</span>
</li>`;
})
.join('\n')}
</ul>
</div>`;
}
if (!isEmptyObject(awayCards)) {
markup += `<div class="goal-scorers__group player-sent-off">
<ul>
${Object.keys(awayCards)
.map(playerId => {
return awayCards[playerId].map((hcPlayer, index) => {
let clsName;
if (index === 0 && awayCards[playerId][index].type === 'YC') {
clsName = 'yellowcard';
} else if (index === 1 && awayCards[playerId][index].type === 'YC') {
clsName = 'yellowredcard';
} else {
clsName = '';
}
return `
<li class="${clsName}">
<span class="scorer-firstname"></span>${awayCards[playerId][0].playerName}
<span class="goal-time">
(${hcPlayer.timeMin}′)
</span>
</li>`;
}).join('\n')
})
.join('\n')}
</ul>
</div>`;
}
if (!isEmptyObject(awayMissedPens)) {
markup += `<div class="goal-scorers__group missed-a-penalty">
<ul>
${Object.keys(awayMissedPens)
.map(playerId => {
return `<li>
<span class="scorer-firstname"></span>${awayMissedPens[playerId][0].playerName}
<span class="goal-time">
${awayMissedPens[playerId].map(player => {
return `(${player.timeMin}′ MISSED PEN)`;
}).join('\n')}
</span>
</li>`;
})
.join('\n')}
</ul>
</div>`;
}
return markup;
};
// will update middle section
const renderScoreLineTeamGoals = ({
matchDetails: {scores}
}) => {
const {ft, ht, et } = scores;
const markup = `
<div class="scoreline__team-goals--scored scoreline__team-goals--live-score">
${ft && !isEmptyObject(ft) ? `<span>${scores.ft.home}</span><span>${scores.ft.away}</span>` : ``}
</div>
<div class="scoreline__team-goals--time">
${ht && !isEmptyObject(ht) ? `<span class='scoreline__team-goals--ht'> HT: ${ht.home}-${ht.away} </span>` : ``}
${et && !isEmptyObject(et) ? `<span class='scoreline__team-goals--ft'> FT: ${et.home}-${et.away} </span>` : ``}
</div>
`;
return markup;
};
// entry point for content update
const updateContent = (parentEl, liveData, contestantIds) => {
const {
matchDetails: {matchLengthMin},
} = liveData;
// 1. update minutes / match length
parentEl.querySelector(
'[data-behaviour="match-length"]'
).innerHTML = matchLengthMin;
// 2. updates the current score and half time/ full time score
parentEl.querySelector(
'[data-behaviour="team-goals-scored"]'
).innerHTML = renderScoreLineTeamGoals(liveData);
// 3. update home team goal score
parentEl.querySelector(
'[data-behaviour=home-team]'
).innerHTML = renderGoalScorerHomeTeam(liveData, contestantIds);
// 4. update away team goal score
parentEl.querySelector(
'[data-behaviour=away-team]'
).innerHTML = renderGoalScorerAwayTeam(liveData, contestantIds);
};
// forms an object with key as `team` and value as `contestant id`
const getContestandIdsByTeam = contestants => {
const result = {};
contestants.forEach(contestant => {
result[contestant.position] = contestant.id;
});
return result;
}
export default parentEl => {
const { matchId } = parentEl.dataset;
if (!matchId) {
throw new Error('invalid match id');
}
try {
const intervalId = setInterval(() => {
fetchLiveScore(matchId).then(response => {
if (!Object.keys(response).length) {
// stop if there is no response
// do we need a refresh?
clearInterval(intervalId);
return;
}
const { matchInfo: { contestant }, liveData } = response;
const contestantIds = getContestandIdsByTeam(contestant);
updateContent(parentEl, liveData, contestantIds);
});
}, POLL_TIMING);
} catch (e) {
throw new Error('Uable to retrive match score ::', e);
}
};
.match-score {
display: grid;
grid-gap: 2rem;
margin-bottom: 3rem;
transform: translateY(-3rem);
position: relative;
&__scoreline {
background: $white;
border-radius: 0.8rem;
padding-top: 1.6rem;
}
@media (max-width: $mq-medium) {
grid-template-areas:
'middle middle'
'left right';
&__goalscorers-left {
grid-area: left;
}
&__scoreline {
grid-row: 1;
grid-area: middle;
margin: 0 0.8rem;
}
&__goalscorers-right {
grid-area: right;
}
}
@media (min-width: $mq-medium) {
display: grid;
grid-template-columns: 1fr 1.5fr 1fr;
margin: 0 auto;
margin-bottom: 3rem;
&__goalscorers-left {
margin-top: 3rem;
padding-top: 2rem;
}
&__goalscorers-right {
margin-top: 3rem;
padding-top: 2rem;
}
}
@media (min-width: $mq-large) {
grid-template-columns: 1fr 2fr 1fr;
}
}
<div class="match-score" {{#if liveScore}} data-behaviour='match-score-live' data-match-id="{{matchId}}" {{/if}}>
<div class="match-score__goalscorers-left">
{{render '@goal-scorers'}}
</div>
<div class="match-score__scoreline">
{{#unless liveScore}}
{{render '@scoreline'}}
{{else}}
{{render '@scoreline--live-score' this merge="true"}}
{{/unless}}
</div>
<div class="match-score__goalscorers-right">
{{render '@goal-scorers--invert'}}
</div>
</div>