mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: add Summoner's games with friends stats
This commit is contained in:
parent
a0b85e888f
commit
4aad54972e
12 changed files with 272 additions and 48 deletions
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<li class="relative">
|
<li class="relative">
|
||||||
<div class="game-status absolute left-0 h-32 w-32">
|
<!-- <div class="game-status absolute left-0 h-32 w-32">
|
||||||
<div class="text-2xl text-teal-500 uppercase font-extrabold">{{ data.status }}</div>
|
<div class="text-2xl text-teal-500 uppercase font-extrabold">{{ data.status }}</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div
|
<div
|
||||||
:class="matchResultClass"
|
:class="matchResultClass"
|
||||||
class="ml-10 match relative mt-4 rounded-lg text-white text-base"
|
class="ml-4 match relative mt-4 bg-blue-800 rounded-lg text-white text-base"
|
||||||
>
|
>
|
||||||
<div class="relative z-20 flex flex-wrap px-5 py-3">
|
<div class="relative z-20 flex flex-wrap px-5 py-3">
|
||||||
<div class="first w-1/3 text-left">
|
<div class="first w-4/12 text-left">
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="h-6 text-lg text-teal-500 font-extrabold uppercase leading-none"
|
class="h-6 text-lg text-teal-500 font-extrabold uppercase leading-none"
|
||||||
|
|
@ -49,15 +49,15 @@
|
||||||
class="w-6 h-6 bg-blue-1000 rounded-md"
|
class="w-6 h-6 bg-blue-1000 rounded-md"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-12 flex flex-col justify-center items-center leading-none">
|
<div class="mx-auto flex flex-col justify-center items-center leading-none">
|
||||||
<div class="text-3xl font-extrabold text-teal-500">
|
<div class="text-xl font-extrabold text-teal-500">
|
||||||
<span class>{{ data.kills }}</span>
|
<span class>{{ data.kills }}</span>
|
||||||
<span class>/</span>
|
<span class>/</span>
|
||||||
<span class>{{ data.deaths }}</span>
|
<span class>{{ data.deaths }}</span>
|
||||||
<span class>/</span>
|
<span class>/</span>
|
||||||
<span class>{{ data.assists }}</span>
|
<span class>{{ data.assists }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2 text-white text-sm font-extrabold">{{ data.kda }} KDA</div>
|
<div class="mt-2 text-white text-xs font-extrabold">{{ data.kda }} KDA</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="second w-1/3 py-6 flex items-center">
|
<div class="second w-3/12 py-6 flex items-center">
|
||||||
<div class="items flex flex-wrap">
|
<div class="items flex flex-wrap">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in data.items"
|
v-for="(item, index) in data.items"
|
||||||
|
|
@ -77,49 +77,49 @@
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ml-12 leading-none">
|
<div class="ml-4 leading-none">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="@/assets/img/icons/Creep.svg" alt="Minions" />
|
<img src="@/assets/img/icons/Creep.svg" alt="Minions" />
|
||||||
<div class="ml-1 text-teal-300 text-lg font-bold">
|
<div class="ml-1 text-teal-300 text-sm font-bold">
|
||||||
{{ data.minions }}
|
{{ data.minions }}
|
||||||
<span class="font-normal">cs</span>
|
<span class="font-normal">cs</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="@/assets/img/icons/Gold.svg" alt="Gold" />
|
<img src="@/assets/img/icons/Gold.svg" alt="Gold" />
|
||||||
<div class="ml-1 gold text-lg font-bold">
|
<div class="ml-1 gold text-sm font-bold">
|
||||||
{{ data.gold }}
|
{{ data.gold }}
|
||||||
<span class="font-normal">gold</span>
|
<!-- <span class="font-normal">gold</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="@/assets/img/icons/Damage.svg" alt="Damage" />
|
<img src="@/assets/img/icons/Damage.svg" alt="Damage" />
|
||||||
<div class="ml-1 damage text-lg font-bold">
|
<div class="ml-1 damage text-sm font-bold">
|
||||||
{{ data.damage }}
|
{{ data.damage }}
|
||||||
<span class="font-normal">damage</span>
|
<!-- <span class="font-normal">dmg</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<img src="@/assets/img/icons/KillParticipation.svg" alt="KillParticipation" />
|
<img src="@/assets/img/icons/KillParticipation.svg" alt="KillParticipation" />
|
||||||
<div class="ml-1 kp text-lg font-bold">
|
<div class="ml-1 kp text-sm font-bold">
|
||||||
{{ data.kp }}
|
{{ data.kp }}
|
||||||
<span class="font-normal">kp</span>
|
<!-- <span class="font-normal">kp</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="third w-1/3 py-1 flex items-center">
|
<div class="third w-5/12 py-1 flex items-center">
|
||||||
<div v-if="data.allyTeam.length > 1">
|
<div v-if="data.allyTeam.length > 1">
|
||||||
<div
|
<div
|
||||||
v-for="(ally, index) in data.allyTeam"
|
v-for="(ally, index) in data.allyTeam"
|
||||||
:key="'player-' + index"
|
:key="'player-' + index"
|
||||||
class="flex items-center leading-none"
|
class="ml-4 flex items-center leading-none"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'summoner', params: { region: $route.params.region, name: ally.name }}"
|
:to="{ name: 'summoner', params: { region: $route.params.region, name: ally.name }}"
|
||||||
:class="isSummonerProfile(ally.name)"
|
:class="isSummonerProfile(ally.name)"
|
||||||
class="w-20 text-right overflow-hidden text-overflow whitespace-no-wrap text-sm text-blue-200 font-medium hover:text-blue-100"
|
class="w-16 text-right overflow-hidden text-overflow whitespace-no-wrap text-xs text-blue-200 font-medium hover:text-blue-100"
|
||||||
>{{ ally.name }}</router-link>
|
>{{ ally.name }}</router-link>
|
||||||
<div
|
<div
|
||||||
:class="index !== 0 ? '-mt-1': ''"
|
:class="index !== 0 ? '-mt-1': ''"
|
||||||
|
|
@ -137,7 +137,7 @@
|
||||||
></div>
|
></div>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'summoner', params: { region: $route.params.region, name: data.enemyTeam[index].name }}"
|
:to="{ name: 'summoner', params: { region: $route.params.region, name: data.enemyTeam[index].name }}"
|
||||||
class="ml-1 w-20 text-left overflow-hidden text-overflow whitespace-no-wrap text-sm text-blue-200 font-medium hover:text-blue-100"
|
class="ml-1 w-16 text-left overflow-hidden text-overflow whitespace-no-wrap text-xs text-blue-200 font-medium hover:text-blue-100"
|
||||||
>{{ data.enemyTeam[index].name }}</router-link>
|
>{{ data.enemyTeam[index].name }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -189,11 +189,11 @@ export default {
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.match {
|
.match {
|
||||||
background-image: linear-gradient(
|
/* background-image: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
#2c5282 0%,
|
#2c5282 0%,
|
||||||
rgba(44, 82, 130, 0) 100%
|
rgba(44, 82, 130, 0) 100%
|
||||||
);
|
); */
|
||||||
}
|
}
|
||||||
|
|
||||||
.match::after {
|
.match::after {
|
||||||
|
|
@ -233,6 +233,7 @@ export default {
|
||||||
|
|
||||||
.game-status {
|
.game-status {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
left: 6px;
|
||||||
transform: translateY(-50%) rotate(-90deg);
|
transform: translateY(-50%) rotate(-90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
130
client/src/components/Summoner/SummonerMates.vue
Normal file
130
client/src/components/Summoner/SummonerMates.vue
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
<template>
|
||||||
|
<div class="bg-blue-800 rounded-lg">
|
||||||
|
<div class="pb-2">
|
||||||
|
<div class="flex items-center justify-center py-4 heading rounded-t-lg text-blue-200">
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5"
|
||||||
|
style="transform: rotate(-5deg);"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
|
||||||
|
<circle cx="9" cy="7" r="4" />
|
||||||
|
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
|
||||||
|
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
||||||
|
</svg>
|
||||||
|
<span class="mx-4 text-lg font-bold uppercase">FRIENDS</span>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5"
|
||||||
|
style="transform: rotate(5deg);"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
|
||||||
|
<circle cx="9" cy="7" r="4" />
|
||||||
|
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
|
||||||
|
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div v-if="hasMates" class="px-4 py-2 text-sm text-left">
|
||||||
|
<div class="flex font-bold text-base text-teal-400">
|
||||||
|
<div class="w-2/4">Summoner</div>
|
||||||
|
<div class="w-1/4">W / L</div>
|
||||||
|
<div class="w-1/4">Winrate</div>
|
||||||
|
</div>
|
||||||
|
<ul class="mt-1 text-gray-100">
|
||||||
|
<li v-for="mate in mates" :key="mate.name" class="flex justify-between items-center">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'summoner', params: { region: $route.params.region, name: mate.name }}"
|
||||||
|
class="w-2/4 hover:text-teal-200"
|
||||||
|
>{{ mate.name }}</router-link>
|
||||||
|
<div class="w-1/4">{{ mate.wins }} / {{ mate.losses }}</div>
|
||||||
|
<div class="w-1/4">
|
||||||
|
<Dropdown>
|
||||||
|
<template v-slot:trigger>
|
||||||
|
<div class="bg-blue-900 rounded-full h-2 cursor-pointer">
|
||||||
|
<div
|
||||||
|
:class="getWinrateColor(mate.winrate)"
|
||||||
|
:style="{width: mate.winrate}"
|
||||||
|
class="rounded-full h-full"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot:default>
|
||||||
|
<div class="px-2 text-white text-center text-xs">
|
||||||
|
<div>Winrate</div>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
:class="getWinrateColor(mate.winrate, false)"
|
||||||
|
class="font-bold"
|
||||||
|
>{{ mate.winrate }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-else class="px-4 py-2 text-center">
|
||||||
|
<div>No friends have been found.</div>
|
||||||
|
<div>😕</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
import Dropdown from '@/components/Dropdown.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Dropdown,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
hasMates() {
|
||||||
|
return this.mates.length > 0
|
||||||
|
},
|
||||||
|
...mapState({
|
||||||
|
mates: state => state.summoner.infos.mates
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getWinrateColor(winrate, background = true) {
|
||||||
|
winrate = winrate.slice(0, -1)
|
||||||
|
if (winrate >= 70) {
|
||||||
|
return background ? 'bg-yellow-400' : 'text-yellow-400'
|
||||||
|
} else if (winrate >= 60) {
|
||||||
|
return background ? 'bg-teal-500' : 'text-teal-500'
|
||||||
|
} else if (winrate >= 50) {
|
||||||
|
return background ? 'bg-teal-300' : 'text-teal-300'
|
||||||
|
}
|
||||||
|
return background ? 'bg-teal-200' : 'text-teal-200'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.heading {
|
||||||
|
background: linear-gradient(
|
||||||
|
to top,
|
||||||
|
rgb(34, 92, 155) 0%,
|
||||||
|
rgb(34, 92, 135) 100%
|
||||||
|
);
|
||||||
|
box-shadow: rgba(235, 248, 255, 0.1) 0px -1px inset;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -29,14 +29,25 @@ export function createMatchData(matches) {
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of teammates of the summoner in a nice way
|
||||||
|
* @param {Object} mates : mates list from the API
|
||||||
|
*/
|
||||||
|
export function createMatesData(mates) {
|
||||||
|
return mates
|
||||||
|
.map(mate => {
|
||||||
|
mate.total = mate.wins + mate.losses
|
||||||
|
mate.winrate = +(100 * mate.wins / mate.total).toFixed(1) + '%'
|
||||||
|
return mate
|
||||||
|
})
|
||||||
|
.sort((a, b) => (a.total < b.total) ? 1 : -1)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all the infos about a summoner built with the Riot API data
|
* Return all the infos about a summoner built with the Riot API data
|
||||||
* @param {Object} RiotData : all data from the Riot API
|
* @param {Object} RiotData : all data from the Riot API
|
||||||
*/
|
*/
|
||||||
export function createSummonerData(RiotData) {
|
export function createSummonerData(RiotData) {
|
||||||
console.log('--- ALL INFOS ---')
|
|
||||||
console.log(RiotData)
|
|
||||||
|
|
||||||
// Ranked Stats
|
// Ranked Stats
|
||||||
RiotData.ranked.soloQ = getLeagueData(RiotData.ranked.soloQ, 'Solo/Duo')
|
RiotData.ranked.soloQ = getLeagueData(RiotData.ranked.soloQ, 'Solo/Duo')
|
||||||
if (!RiotData.ranked.soloQ) delete RiotData.ranked.soloQ
|
if (!RiotData.ranked.soloQ) delete RiotData.ranked.soloQ
|
||||||
|
|
@ -65,6 +76,7 @@ export function createSummonerData(RiotData) {
|
||||||
ranked: RiotData.ranked,
|
ranked: RiotData.ranked,
|
||||||
matchList: RiotData.allMatches,
|
matchList: RiotData.allMatches,
|
||||||
matches: createMatchData(RiotData.matchesDetails),
|
matches: createMatchData(RiotData.matchesDetails),
|
||||||
|
mates: createMatesData(RiotData.mates),
|
||||||
playing: RiotData.playing
|
playing: RiotData.playing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { axios } from '@/plugins/axios'
|
import { axios } from '@/plugins/axios'
|
||||||
import { createMatchData, createSummonerData } from '@/helpers/summoner'
|
import { createMatchData, createMatesData, createSummonerData } from '@/helpers/summoner'
|
||||||
|
|
||||||
export const namespaced = true
|
export const namespaced = true
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ export const state = {
|
||||||
matchIndex: 0,
|
matchIndex: 0,
|
||||||
matchList: [],
|
matchList: [],
|
||||||
matches: [],
|
matches: [],
|
||||||
|
mates: [],
|
||||||
ranked: {},
|
ranked: {},
|
||||||
playing: false
|
playing: false
|
||||||
},
|
},
|
||||||
|
|
@ -20,12 +21,14 @@ export const mutations = {
|
||||||
MATCHES_LOADING(state) {
|
MATCHES_LOADING(state) {
|
||||||
state.matchesLoading = true
|
state.matchesLoading = true
|
||||||
},
|
},
|
||||||
MATCHES_FOUND(state, newMatches) {
|
MATCHES_FOUND(state, { newMatches, mates }) {
|
||||||
state.matchesLoading = false
|
state.matchesLoading = false
|
||||||
|
|
||||||
state.infos.matches = [...state.infos.matches, ...newMatches]
|
state.infos.matches = [...state.infos.matches, ...newMatches]
|
||||||
|
|
||||||
state.infos.matchIndex += newMatches.length
|
state.infos.matchIndex += newMatches.length
|
||||||
|
|
||||||
|
state.infos.mates = mates
|
||||||
},
|
},
|
||||||
SUMMONER_REQUEST(state) {
|
SUMMONER_REQUEST(state) {
|
||||||
state.status = 'loading'
|
state.status = 'loading'
|
||||||
|
|
@ -36,6 +39,7 @@ export const mutations = {
|
||||||
state.infos.matches = infos.matches
|
state.infos.matches = infos.matches
|
||||||
state.infos.ranked = infos.ranked
|
state.infos.ranked = infos.ranked
|
||||||
state.infos.matchIndex = infos.matches.length
|
state.infos.matchIndex = infos.matches.length
|
||||||
|
state.infos.mates = infos.mates
|
||||||
state.infos.playing = infos.playing
|
state.infos.playing = infos.playing
|
||||||
state.status = 'found'
|
state.status = 'found'
|
||||||
},
|
},
|
||||||
|
|
@ -52,7 +56,11 @@ export const actions = {
|
||||||
const gameIds = state.infos.matchList.slice(state.infos.matchIndex, state.infos.matchIndex + 10).map(({ gameId }) => gameId)
|
const gameIds = state.infos.matchList.slice(state.infos.matchIndex, state.infos.matchIndex + 10).map(({ gameId }) => gameId)
|
||||||
|
|
||||||
const resp = await axios(({ url: 'match', data: { account, gameIds }, method: 'POST' })).catch(() => { })
|
const resp = await axios(({ url: 'match', data: { account, gameIds }, method: 'POST' })).catch(() => { })
|
||||||
commit('MATCHES_FOUND', createMatchData(resp.data))
|
console.log('--- MATCHES INFOS ---')
|
||||||
|
console.log(resp.data)
|
||||||
|
const newMatches = createMatchData(resp.data.matches)
|
||||||
|
const mates = createMatesData(resp.data.mates)
|
||||||
|
commit('MATCHES_FOUND', { newMatches, mates })
|
||||||
},
|
},
|
||||||
async summonerRequest({ commit, dispatch, rootState }, { summoner, region }) {
|
async summonerRequest({ commit, dispatch, rootState }, { summoner, region }) {
|
||||||
region = rootState.regionsList[region]
|
region = rootState.regionsList[region]
|
||||||
|
|
@ -60,6 +68,8 @@ export const actions = {
|
||||||
try {
|
try {
|
||||||
const resp = await axios(({ url: 'api', data: { summoner, region }, method: 'POST' }))
|
const resp = await axios(({ url: 'api', data: { summoner, region }, method: 'POST' }))
|
||||||
if (resp.data) {
|
if (resp.data) {
|
||||||
|
console.log('--- SUMMONER INFOS ---')
|
||||||
|
console.log(resp.data)
|
||||||
dispatch('ddragon/getVersion', resp.data.version, { root: true })
|
dispatch('ddragon/getVersion', resp.data.version, { root: true })
|
||||||
const infos = createSummonerData(resp.data)
|
const infos = createSummonerData(resp.data)
|
||||||
commit('SUMMONER_FOUND', infos)
|
commit('SUMMONER_FOUND', infos)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="bg-blue-900 overflow-hidden min-h-screen flex flex-col">
|
<div class="bg-blue-900 overflow-hidden min-h-screen flex flex-col">
|
||||||
<LazyBackground
|
<LazyBackground
|
||||||
:image-source="require('@/assets/img/bg-homepage-1.jpg')"
|
:image-source="require('@/assets/img/bg-homepage-1.jpg')"
|
||||||
image-class="fixed w-full h-200 z-0"
|
image-class="absolute w-full h-200 z-0"
|
||||||
more-backgrounds="linear-gradient(180deg, rgba(42, 67, 101, 0) 0%, #2A4365 50%),"
|
more-backgrounds="linear-gradient(180deg, rgba(42, 67, 101, 0) 0%, #2A4365 50%),"
|
||||||
transition-name="fade"
|
transition-name="fade"
|
||||||
></LazyBackground>
|
></LazyBackground>
|
||||||
|
|
@ -60,8 +60,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-12 text-center">
|
<div class="mt-12 text-center flex">
|
||||||
<ul class="text-gray-900">
|
<div class="mt-4 w-3/12">
|
||||||
|
<SummonerMates />
|
||||||
|
</div>
|
||||||
|
<ul class="w-9/12 text-gray-900">
|
||||||
<Match
|
<Match
|
||||||
v-for="(match, index) in summonerInfos.matches"
|
v-for="(match, index) in summonerInfos.matches"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|
@ -103,10 +106,11 @@ import LazyBackground from '@/components/LazyBackgroundImage.vue'
|
||||||
import LoadingButton from '@/components/LoadingButton.vue'
|
import LoadingButton from '@/components/LoadingButton.vue'
|
||||||
import MainFooter from '@/components/MainFooter.vue'
|
import MainFooter from '@/components/MainFooter.vue'
|
||||||
import Match from '@/components/Match.vue'
|
import Match from '@/components/Match.vue'
|
||||||
import RecentActivity from '@/components/RecentActivity.vue'
|
import RecentActivity from '@/components/Summoner/RecentActivity.vue'
|
||||||
import SearchForm from '@/components/SearchForm.vue'
|
import SearchForm from '@/components/SearchForm.vue'
|
||||||
import SummonerLoader from '@/components/SummonerLoader.vue'
|
import SummonerLoader from '@/components/Summoner/SummonerLoader.vue'
|
||||||
import SummonerRanked from '@/components/SummonerRanked.vue'
|
import SummonerMates from '@/components/Summoner/SummonerMates.vue'
|
||||||
|
import SummonerRanked from '@/components/Summoner/SummonerRanked.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -117,6 +121,7 @@ export default {
|
||||||
RecentActivity,
|
RecentActivity,
|
||||||
SearchForm,
|
SearchForm,
|
||||||
SummonerLoader,
|
SummonerLoader,
|
||||||
|
SummonerMates,
|
||||||
SummonerRanked,
|
SummonerRanked,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const MatchHelper = use('App/Helpers/MatchHelper')
|
const MatchHelper = use('App/Helpers/MatchHelper')
|
||||||
|
const Summoner = use('App/Models/Summoner')
|
||||||
|
|
||||||
class MatchController {
|
class MatchController {
|
||||||
/**
|
/**
|
||||||
|
|
@ -11,8 +12,15 @@ class MatchController {
|
||||||
const account = request.input('account')
|
const account = request.input('account')
|
||||||
const gameIds = request.input('gameIds')
|
const gameIds = request.input('gameIds')
|
||||||
|
|
||||||
const result = await MatchHelper.getMatches(account, gameIds)
|
const summonerDB = await Summoner.where({ puuid: account.puuid }).first()
|
||||||
return response.json(result)
|
const matches = await MatchHelper.getMatches(account, gameIds, summonerDB)
|
||||||
|
|
||||||
|
await summonerDB.save()
|
||||||
|
|
||||||
|
return response.json({
|
||||||
|
matches,
|
||||||
|
mates: summonerDB.mates.filter(m => m.wins + m.losses > 1)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
const Jax = use('Jax')
|
const Jax = use('Jax')
|
||||||
const MatchHelper = use('App/Helpers/MatchHelper')
|
const MatchHelper = use('App/Helpers/MatchHelper')
|
||||||
|
const Summoner = use('App/Models/Summoner')
|
||||||
|
|
||||||
class SummonerController {
|
class SummonerController {
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,9 +29,16 @@ class SummonerController {
|
||||||
account.region = region
|
account.region = region
|
||||||
finalJSON.account = account
|
finalJSON.account = account
|
||||||
|
|
||||||
|
// Summoner in DB
|
||||||
|
let summonerDB = await Summoner.where({ puuid: account.puuid }).first()
|
||||||
|
if (!summonerDB) {
|
||||||
|
summonerDB = await Summoner.create({ puuid: account.puuid })
|
||||||
|
}
|
||||||
|
|
||||||
// CURRENT GAME
|
// CURRENT GAME
|
||||||
const currentGame = await Jax.Spectator.summonerID(account.id)
|
const currentGame = await Jax.Spectator.summonerID(account.id)
|
||||||
finalJSON.playing = !!currentGame
|
finalJSON.playing = !!currentGame
|
||||||
|
|
||||||
// RANKED STATS
|
// RANKED STATS
|
||||||
const ranked = await Jax.League.summonerID(account.id)
|
const ranked = await Jax.League.summonerID(account.id)
|
||||||
finalJSON.ranked = {
|
finalJSON.ranked = {
|
||||||
|
|
@ -40,15 +48,22 @@ class SummonerController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MATCH LIST
|
// MATCH LIST
|
||||||
const matchList = await MatchHelper.getFullMatchList(account)
|
await MatchHelper.updateMatchList(account, summonerDB)
|
||||||
|
const matchList = summonerDB.matchList
|
||||||
finalJSON.allMatches = matchList
|
finalJSON.allMatches = matchList
|
||||||
|
|
||||||
// MATCHES DETAILS
|
// MATCHES DETAILS
|
||||||
const gameIds = matchList.slice(0, 10).map(({ gameId }) => gameId)
|
const gameIds = matchList.slice(0, 10).map(({ gameId }) => gameId)
|
||||||
finalJSON.matchesDetails = await MatchHelper.getMatches(account, gameIds)
|
finalJSON.matchesDetails = await MatchHelper.getMatches(account, gameIds, summonerDB)
|
||||||
|
|
||||||
|
// MATES
|
||||||
|
finalJSON.mates = summonerDB.mates.filter(m => m.wins + m.losses > 1)
|
||||||
|
|
||||||
// PATCH VERSION
|
// PATCH VERSION
|
||||||
finalJSON.version = Jax.DDragon.Version
|
finalJSON.version = Jax.DDragon.Version
|
||||||
|
|
||||||
|
// SAVE IN DB
|
||||||
|
await summonerDB.save()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('username not found')
|
console.log('username not found')
|
||||||
console.log(error)
|
console.log(error)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ const Match = use('App/Models/Match')
|
||||||
const Summoner = use('App/Models/Summoner')
|
const Summoner = use('App/Models/Summoner')
|
||||||
const Jax = use('Jax')
|
const Jax = use('Jax')
|
||||||
const MatchTransformer = use('App/Transformers/MatchTransformer')
|
const MatchTransformer = use('App/Transformers/MatchTransformer')
|
||||||
|
const SummonerHelper = use('App/Helpers/SummonerHelper')
|
||||||
|
|
||||||
class MatchHelper {
|
class MatchHelper {
|
||||||
/**
|
/**
|
||||||
|
|
@ -34,15 +35,15 @@ class MatchHelper {
|
||||||
return matchList
|
return matchList
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Return the full MatchList of the summoner (min. 4 months)
|
* Update the full MatchList of the summoner (min. 4 months)
|
||||||
* @param account of the summoner
|
* @param account of the summoner
|
||||||
|
* @param summonerDB summoner in the database
|
||||||
*/
|
*/
|
||||||
async getFullMatchList(account) {
|
async updateMatchList(account, summonerDB) {
|
||||||
console.time('matchList')
|
console.time('matchList')
|
||||||
let summonerDB = await Summoner.where({ puuid: account.puuid }).first()
|
|
||||||
|
|
||||||
// Summoner has already been searched : we already have a MatchList and we need to update it
|
// Summoner has already been searched : we already have a MatchList and we need to update it
|
||||||
if (summonerDB) {
|
if (summonerDB.matchList) {
|
||||||
// Get MatchList
|
// Get MatchList
|
||||||
const matchList = await this.fetchMatchListUntil(account, (newMatchList) => {
|
const matchList = await this.fetchMatchListUntil(account, (newMatchList) => {
|
||||||
return summonerDB.matchList.some(m => m.gameId === newMatchList[newMatchList.length - 1].gameId)
|
return summonerDB.matchList.some(m => m.gameId === newMatchList[newMatchList.length - 1].gameId)
|
||||||
|
|
@ -54,7 +55,6 @@ class MatchHelper {
|
||||||
summonerDB.matchList.unshift(match)
|
summonerDB.matchList.unshift(match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await summonerDB.save()
|
|
||||||
Logger.transport('file').info(`Summoner ${account.name} has been updated.`)
|
Logger.transport('file').info(`Summoner ${account.name} has been updated.`)
|
||||||
}
|
}
|
||||||
// First search of the Summoner
|
// First search of the Summoner
|
||||||
|
|
@ -64,21 +64,20 @@ class MatchHelper {
|
||||||
const matchList = await this.fetchMatchListUntil(account, (newMatchList) => {
|
const matchList = await this.fetchMatchListUntil(account, (newMatchList) => {
|
||||||
return (newMatchList.length !== 100 || today - newMatchList[newMatchList.length - 1].timestamp > 10368000000)
|
return (newMatchList.length !== 100 || today - newMatchList[newMatchList.length - 1].timestamp > 10368000000)
|
||||||
})
|
})
|
||||||
// Create Summoner in Database
|
// Create Summoner's MatchList in Database
|
||||||
summonerDB = await Summoner.create({ puuid: account.puuid, matchList: matchList })
|
summonerDB.matchList = matchList
|
||||||
Logger.transport('file').info(`Summoner ${account.name} has been created.`)
|
Logger.transport('file').info(`Summoner ${account.name} has been created.`)
|
||||||
}
|
}
|
||||||
console.timeEnd('matchList')
|
console.timeEnd('matchList')
|
||||||
|
|
||||||
return summonerDB.matchList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch list of matches for a specific Summoner
|
* Fetch list of matches for a specific Summoner
|
||||||
* @param account of the summoner
|
* @param account of the summoner
|
||||||
* @param gameIds of the matches to fetch
|
* @param gameIds of the matches to fetch
|
||||||
|
* @param summonerDB summoner in the database
|
||||||
*/
|
*/
|
||||||
async getMatches(account, gameIds) {
|
async getMatches(account, gameIds, summonerDB) {
|
||||||
console.time('getMatches')
|
console.time('getMatches')
|
||||||
|
|
||||||
let matchesDetails = []
|
let matchesDetails = []
|
||||||
|
|
@ -113,6 +112,9 @@ class MatchHelper {
|
||||||
.withContext(ctx)
|
.withContext(ctx)
|
||||||
.toJSON()
|
.toJSON()
|
||||||
|
|
||||||
|
// Update teamMates
|
||||||
|
SummonerHelper.updatePlayedWith(account, summonerDB, matchesFromApi)
|
||||||
|
|
||||||
matchesDetails = [...matchesDetails, ...matchesFromApi]
|
matchesDetails = [...matchesDetails, ...matchesFromApi]
|
||||||
|
|
||||||
/* Save all matches from Riot Api in db */
|
/* Save all matches from Riot Api in db */
|
||||||
|
|
|
||||||
41
server/app/Helpers/SummonerHelper.js
Normal file
41
server/app/Helpers/SummonerHelper.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const Logger = use('Logger')
|
||||||
|
const Summoner = use('App/Models/Summoner')
|
||||||
|
|
||||||
|
class SummonerHelper {
|
||||||
|
/**
|
||||||
|
* Update the mates' list of the Summoner
|
||||||
|
* @param account of the summoner
|
||||||
|
* @param summonerDB summoner in the database
|
||||||
|
* @param matches all new matches
|
||||||
|
*/
|
||||||
|
updatePlayedWith(account, summonerDB, matches) {
|
||||||
|
let teamMates = summonerDB.mates || []
|
||||||
|
|
||||||
|
for (const match of matches) {
|
||||||
|
const win = match.result === 'Win'
|
||||||
|
|
||||||
|
for (const ally of match.allyTeam) {
|
||||||
|
if (ally.name === account.name) continue
|
||||||
|
|
||||||
|
const mate = teamMates.find(m => m.name === ally.name)
|
||||||
|
if (mate) {
|
||||||
|
win ? mate.wins++ : mate.losses++
|
||||||
|
} else {
|
||||||
|
teamMates.push({
|
||||||
|
name: ally.name,
|
||||||
|
wins: win ? 1 : 0,
|
||||||
|
losses: win ? 0 : 1,
|
||||||
|
creation: Date.now()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save new mates'list
|
||||||
|
summonerDB.mates = teamMates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new SummonerHelper()
|
||||||
Loading…
Reference in a new issue