some more refactoring

This commit is contained in:
cnachtigall1991
2021-10-17 18:06:28 +02:00
parent 6ffd7685ab
commit 123f78cb21
5 changed files with 364 additions and 167 deletions

View File

@@ -4,9 +4,22 @@ export default createStore({
state: { state: {
id64: '', id64: '',
vanityUrl: '', vanityUrl: '',
matchDetails: {} matchDetails: {},
playerDetails: {}
}, },
mutations: { mutations: {
changeId64(state, payload) {
state.id64 = payload.id
},
changeVanityUrl(state, payload) {
state.vanityUrl = payload.id
},
changeMatchDetails(state, payload) {
state.matchDetails = payload.data
},
changePlayerDetails(state, payload) {
state.playerDetails = payload.data
},
}, },
actions: { actions: {
}, },

View File

@@ -45,3 +45,24 @@ export const getPlayerArr = (stats, team, color) => {
return arr return arr
} }
export const constructAvatarUrl = (hash, size) => {
const base = 'https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars'
const imgSize = size ? `_${size}` : ''
const hashDir = hash.substring(0, 2)
return `${base}/${hashDir}/${hash}${imgSize}.jpg`
}
export const GetAvgRank = (stats) => {
let count = 0
let fullRank = 0
stats.map(player => {
if (player.rank?.old) {
fullRank += player.rank?.old
count += 1
}
})
return count === 0 ? 0 : Math.floor(fullRank / count)
}

View File

@@ -4,7 +4,7 @@ import {SaveLastVisitedToLocalStorage} from "./LocalStorage";
import {GetHLTV_1} from "./HLTV"; import {GetHLTV_1} from "./HLTV";
import {DisplayRank, LoadImage} from "./Display"; import {DisplayRank, LoadImage} from "./Display";
import {GetUser, TrackMe} from "./ApiRequests"; import {GetUser, TrackMe} from "./ApiRequests";
import {setTitle, GetWinLoss, truncate, checkStatEmpty, getPlayerArr} from "./Utils"; import {setTitle, GetWinLoss, truncate, checkStatEmpty, getPlayerArr, constructAvatarUrl, GetAvgRank} from "./Utils";
export { export {
FormatDate, FormatFullDuration, FormatFullDate, FormatDuration, FormatDate, FormatFullDuration, FormatFullDate, FormatDuration,
@@ -13,5 +13,5 @@ export {
GetHLTV_1, GetHLTV_1,
DisplayRank, LoadImage, DisplayRank, LoadImage,
GetUser, TrackMe, GetUser, TrackMe,
setTitle, GetWinLoss, truncate, checkStatEmpty, getPlayerArr setTitle, GetWinLoss, truncate, checkStatEmpty, getPlayerArr, constructAvatarUrl, GetAvgRank
} }

View File

@@ -79,9 +79,9 @@
</template> </template>
<script> <script>
import {onBeforeMount, onMounted, reactive, watch} from "vue"; import {onBeforeMount, onBeforeUnmount, onMounted, reactive, watch} from "vue";
import axios from 'axios' import axios from 'axios'
import {DisplayRank, FormatFullDate, GetHLTV_1, GoToLink, GoToPlayer, LoadImage} from "../utils"; import {DisplayRank, FormatFullDate, GetAvgRank, GoToLink, LoadImage} from "../utils";
import {useStore} from "vuex"; import {useStore} from "vuex";
import {useRoute} from 'vue-router' import {useRoute} from 'vue-router'
@@ -92,7 +92,7 @@ export default {
const store = useStore() const store = useStore()
const route = useRoute() const route = useRoute()
store.state.matchDetails = {} const matchIdPattern = /^\d{19}$/
// Refs // Refs
const data = reactive({ const data = reactive({
@@ -105,56 +105,57 @@ export default {
// Functions // Functions
const GetMatch = () => { const GetMatch = () => {
axios if (matchIdPattern.test(props.match_id))
.get(`${process.env.VUE_APP_API_URL}/match/${props.match_id}`) axios
.then((response) => { .get(`${process.env.VUE_APP_API_URL}/match/${props.match_id}`)
document.title = `${response.data.map} | csgoWTF` .then((response) => {
data.matchDetails = response.data document.title = `${response.data.map} | csgoWTF`
data.stats = response.data.stats store.commit({
data.score = response.data.score type: 'changeMatchDetails',
data: response.data
})
store.state.matchDetails = response.data data.matchDetails = store.state.matchDetails
data.stats = data.matchDetails.stats
data.score = data.matchDetails.score
LoadImage(data.matchDetails.map ? data.matchDetails.map : 'random') LoadImage(data.matchDetails.map ? data.matchDetails.map : 'random')
console.log(response.data) GetAvgRank(data.stats)
})
.catch((e) => {
console.log(e)
})
}
const GetAvgRank = () => { console.log(data.matchDetails)
let count = 0 })
let fullRank = 0 .catch((e) => {
console.log(e)
data.stats?.map(player => { // TODO: needs 404
if (player.rank?.old) { })
fullRank += player.rank?.old else {
count += 1 console.log('Match not found')
} // TODO: needs 404
}) }
if (count === 0)
data.avgRank = 0
else
data.avgRank = Math.floor(fullRank / count)
} }
const checkRoute = () => { const checkRoute = () => {
if (route.fullPath.split('/')[3]) { if (route.fullPath.split('/')[3]) {
const sub = route.fullPath.split('/')[3] const sub = route.fullPath.split('/')[3]
GoToLink(`/match/${props.match_id}/${sub}`) if (matchIdPattern.test(props.match_id))
GoToLink(`/match/${props.match_id}/${sub}`)
else {
console.log('Match not found')
// TODO: needs 404
}
} else if (route.fullPath.split('/')[3] === undefined) { } else if (route.fullPath.split('/')[3] === undefined) {
// setTimeout(() => { if (matchIdPattern.test(props.match_id))
GoToLink(`/match/${props.match_id}/overview`) GoToLink(`/match/${props.match_id}/overview`)
// }, 200) else {
console.log('Match not found')
// TODO: needs 404
}
} }
} }
// Watchers // Watchers
watch(() => props.match_id, GetMatch) watch(() => props.match_id, GetMatch)
watch(() => data.stats, GetAvgRank)
// Run on create // Run on create
onBeforeMount(() => { onBeforeMount(() => {
@@ -165,8 +166,15 @@ export default {
checkRoute() checkRoute()
}) })
onBeforeUnmount(() => {
store.commit({
type: 'changeMatchDetails',
data: {}
})
})
return { return {
GetMatch, GetAvgRank, data, GoToPlayer, GetHLTV_1, DisplayRank, FormatFullDate, LoadImage data, DisplayRank, FormatFullDate
} }
} }
} }
@@ -241,6 +249,9 @@ export default {
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
padding-left: 70px;
z-index: 1; z-index: 1;
height: 100%; height: 100%;
width: 100%; width: 100%;
@@ -252,4 +263,11 @@ export default {
rgba(0, 0, 0, .6) 100% rgba(0, 0, 0, .6) 100%
); );
} }
@media screen and (max-width: 991px) {
#scoreWrapper {
overflow-x: scroll;
overflow-y: hidden;
}
}
</style> </style>

View File

@@ -6,10 +6,16 @@
<div class="row g-0"> <div class="row g-0">
<div class="img-container col-md-2 pt-3"> <div class="img-container col-md-2 pt-3">
<img <img
:class="data.tracked ? 'tracked' : ''" :src="data.playerDetails.avatar" :class="data.tracked ? 'tracked' : ''" :src="store.state.playerDetails.avatar"
:title="data.tracked ? 'Tracked' : ''" :title="data.tracked ? 'Tracked' : ''"
alt="Player avatar" alt="Player avatar"
class="img-fluid avatar"> class="img-fluid avatar">
<!-- <img-->
<!-- :class="data.tracked ? 'tracked' : ''"-->
<!-- :src="constructAvatarUrl(store.state.playerDetails.avatar, 'full')"-->
<!-- :title="data.tracked ? 'Tracked' : ''"-->
<!-- alt="Player avatar"-->
<!-- class="img-fluid avatar">-->
</div> </div>
<div class="col-md-8 d-flex"> <div class="col-md-8 d-flex">
<div class="card-body"> <div class="card-body">
@@ -18,7 +24,7 @@
class="text-decoration-none text-white" class="text-decoration-none text-white"
target="_blank" target="_blank"
title="Open steam profile">{{ title="Open steam profile">{{
data.playerDetails.name store.state.playerDetails.name
}} }}
<i class="fas fa-link"></i> <i class="fas fa-link"></i>
</a></h3> </a></h3>
@@ -100,71 +106,72 @@
</div> </div>
</div> </div>
</div> </div>
<div class="matches m-auto"> <div class="match-container">
<table v-if="data.matches" class="table table-borderless"> <div class="matches">
<thead class="border-bottom"> <table v-if="data.matches" class="table table-borderless">
<tr> <thead class="border-bottom">
<th class="text-center map" scope="col">Map</th> <tr>
<th class="text-center rank" scope="col">Rank</th> <th class="text-center map" scope="col">Map</th>
<th class="text-center length" scope="col" title="Match Length"> <th class="text-center rank" scope="col">Rank</th>
<i class="far fa-clock"></i> <th class="text-center length" scope="col" title="Match Length">
</th> <i class="far fa-clock"></i>
<th class="text-center score" scope="col">Score</th> </th>
<th class="text-center kills" scope="col">K</th> <th class="text-center score" scope="col">Score</th>
<th class="text-center assists" scope="col">A</th> <th class="text-center kills" scope="col">K</th>
<th class="text-center deaths" scope="col">D</th> <th class="text-center assists" scope="col">A</th>
<th class="text-center kdiff" scope="col" style="cursor: help" title="Kill-to-death ratio">+/-</th> <th class="text-center deaths" scope="col">D</th>
<th class="text-center hltv" scope="col" style="cursor: help" title="HLTV 1.0 Rating">Rating</th> <th class="text-center kdiff" scope="col" style="cursor: help" title="Kill-to-death ratio">+/-</th>
<th class="text-center duration" scope="col">Duration</th> <th class="text-center hltv" scope="col" style="cursor: help" title="HLTV 1.0 Rating">Rating</th>
<th class="date" scope="col">Date</th> <th class="text-center duration" scope="col">Duration</th>
</tr> <th class="date" scope="col">Date</th>
</thead> </tr>
<tbody> </thead>
<tr v-for="match in data.matches" <tbody>
:key="match.match_id" <tr v-for="match in data.matches"
:class="GetWinLoss(match.match_result, match.stats.team_id)" :key="match.match_id"
class="match" :class="GetWinLoss(match.match_result, match.stats.team_id)"
@click="GoToMatch(match.match_id)"> class="match"
<td class="td-map text-center"> @click="GoToMatch(match.match_id)">
<i v-if="match.parsed" class="far fa-chart-bar parsed" style="cursor: help" <td class="td-map text-center">
title="Demo has been parsed for additional data"></i> <i v-if="match.parsed" class="far fa-chart-bar parsed" style="cursor: help"
<img :alt="match.map ? match.map : 'Map not found'" title="Demo has been parsed for additional data"></i>
:src="match.map !== '' ? require('@/images/map_icons/map_icon_' + match.map + '.svg') : require('../images/map_icons/map_icon_lobby_mapveto.svg')" <img :alt="match.map ? match.map : 'Map not found'"
:title="match.map" :src="match.map !== '' ? require('@/images/map_icons/map_icon_' + match.map + '.svg') : require('../images/map_icons/map_icon_lobby_mapveto.svg')"
class="map-icon"> :title="match.map"
</td> class="map-icon">
<td class="td-rank text-center"> </td>
<img <td class="td-rank text-center">
:alt="DisplayRank(match.stats.rank?.new)[1]" <img
:src="DisplayRank(match.stats.rank?.new)[0]" :alt="DisplayRank(match.stats.rank?.new)[1]"
:title="DisplayRank(match.stats.rank?.new)[1]" :src="DisplayRank(match.stats.rank?.new)[0]"
class="rank-icon"> :title="DisplayRank(match.stats.rank?.new)[1]"
</td> class="rank-icon">
<td class="td-length text-center"> </td>
<i v-if="match.max_rounds === 30 || !match.max_rounds" class="fas fa-circle text-muted" <td class="td-length text-center">
title="Long match"></i> <i v-if="match.max_rounds === 30 || !match.max_rounds" class="fas fa-circle text-muted"
<i v-if="match.max_rounds === 16" class="far fa-circle text-muted" title="Short match"></i> title="Long match"></i>
</td> <i v-if="match.max_rounds === 16" class="far fa-circle text-muted" title="Short match"></i>
<td :class="match.stats.team_id === match.match_result ? 'text-success' : !match.match_result ? 'text-warning' : 'text-danger'" </td>
class="td-score text-center fw-bold"> <td :class="match.stats.team_id === match.match_result ? 'text-success' : !match.match_result ? 'text-warning' : 'text-danger'"
{{ match.score[0] }} - {{ match.score[1] }} class="td-score text-center fw-bold">
</td> {{ match.score[0] }} - {{ match.score[1] }}
<td class="td-kills text-center"> </td>
{{ match.stats.kills ? match.stats.kills : "0" }} <td class="td-kills text-center">
</td> {{ match.stats.kills ? match.stats.kills : "0" }}
<td class="td-assists text-center"> </td>
{{ match.stats.assists ? match.stats.assists : "0" }} <td class="td-assists text-center">
</td> {{ match.stats.assists ? match.stats.assists : "0" }}
<td class="td-deaths text-center"> </td>
{{ match.stats.deaths ? match.stats.deaths : "0" }} <td class="td-deaths text-center">
</td> {{ match.stats.deaths ? match.stats.deaths : "0" }}
<td :class="(match.stats.kills ? match.stats.kills : 0) - (match.stats.deaths ? match.stats.deaths : 0) >= 0 ? 'text-success' : 'text-danger'" </td>
class="td-plus text-center"> <td :class="(match.stats.kills ? match.stats.kills : 0) - (match.stats.deaths ? match.stats.deaths : 0) >= 0 ? 'text-success' : 'text-danger'"
{{ class="td-plus text-center">
(match.stats.kills ? match.stats.kills : 0) - (match.stats.deaths ? match.stats.deaths : 0) {{
}} (match.stats.kills ? match.stats.kills : 0) - (match.stats.deaths ? match.stats.deaths : 0)
</td> }}
<td :class="GetHLTV_1( </td>
<td :class="GetHLTV_1(
match.stats.kills, match.stats.kills,
match.score[0] + match.score[1], match.score[0] + match.score[1],
match.stats.deaths, match.stats.deaths,
@@ -172,36 +179,79 @@
match.stats.multi_kills?.triple, match.stats.multi_kills?.triple,
match.stats.multi_kills?.quad, match.stats.multi_kills?.quad,
match.stats.multi_kills?.pent) >= 1 ? 'text-success' : 'text-warning'" match.stats.multi_kills?.pent) >= 1 ? 'text-success' : 'text-warning'"
class="td-hltv text-center fw-bold"> class="td-hltv text-center fw-bold">
{{ {{
GetHLTV_1( GetHLTV_1(
match.stats.kills, match.stats.kills,
match.score[0] + match.score[1], match.score[0] + match.score[1],
match.stats.deaths, match.stats.deaths,
match.stats.multi_kills?.duo, match.stats.multi_kills?.duo,
match.stats.multi_kills?.triple, match.stats.multi_kills?.triple,
match.stats.multi_kills?.quad, match.stats.multi_kills?.quad,
match.stats.multi_kills?.pent) match.stats.multi_kills?.pent)
}} }}
</td> </td>
<td :title="FormatFullDuration(match.duration)" class="td-duration text-center"> <td :title="FormatFullDuration(match.duration)" class="td-duration text-center">
{{ FormatDuration(match.duration) }} {{ FormatDuration(match.duration) }}
</td> </td>
<td :title="FormatFullDate(match.date)" class="td-date"> <td :title="FormatFullDate(match.date)" class="td-date">
{{ FormatDate(match.date) }} {{ FormatDate(match.date) }}
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h5 v-else>No matches on record</h5> <h5 v-else>No matches on record</h5>
</div>
<div class="side-info">
<div class="side-info-box best-mate">
<div class="heading">
<h5>Best Mate</h5>
</div>
<hr>
<ul class="list-unstyled">
<li>Mate 1</li>
<li>Mate 2</li>
<li>Mate 3</li>
<li>Mate 4</li>
<li>Mate 5</li>
</ul>
</div>
<div class="side-info-box best-mate">
<div class="heading">
<h5>Most played with</h5>
</div>
<hr>
<ul class="list-unstyled">
<li>Player 1</li>
<li>Player 2</li>
<li>Player 3</li>
<li>Player 4</li>
<li>Player 5</li>
</ul>
</div>
<div class="side-info-box best-mate">
<div class="heading">
<h5>Preferred Weapons</h5>
</div>
<hr>
<ul class="list-unstyled">
<li>Weapon 1</li>
<li>Weapon 2</li>
<li>Weapon 3</li>
<li>Weapon 4</li>
<li>Weapon 5</li>
</ul>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import {onMounted, reactive, watch} from "vue"; import {onBeforeUnmount, onMounted, reactive, watch} from "vue";
import {useStore} from "vuex"; import {useStore} from "vuex";
import { import {
DisplayRank, DisplayRank,
@@ -215,7 +265,8 @@ import {
GoToLink, GoToLink,
GoToMatch, GoToMatch,
LoadImage, LoadImage,
SaveLastVisitedToLocalStorage, setTitle, SaveLastVisitedToLocalStorage,
setTitle,
TrackMe TrackMe
} from "../utils"; } from "../utils";
@@ -231,7 +282,6 @@ export default {
authcode: '', authcode: '',
sharecode: '' sharecode: ''
}, },
playerDetails: {},
tracked: false, tracked: false,
matches: [], matches: [],
statusError: '', statusError: '',
@@ -243,43 +293,63 @@ export default {
} }
}) })
const SetPlayerData = () => {
data.tracked = store.state.playerDetails.tracked
data.matches = store.state.playerDetails.matches
data.match_stats.loss = store.state.playerDetails.match_stats.loss || 0
data.match_stats.win = store.state.playerDetails.match_stats.win || 0
data.match_stats.tie = store.state.playerDetails.match_stats.tie || 0
store.commit({
type: 'changeId64',
id: store.state.playerDetails.steamid64
})
store.commit({
type: 'changeVanityUrl',
id: store.state.playerDetails.vanity_url || ''
})
if (data.matches)
LoadImage(data.matches[0].map ? data.matches[0].map : 'random')
let player = {
'steamid64': store.state.playerDetails.steamid64,
'vanity_url': store.state.playerDetails.vanity_url || '',
'name': store.state.playerDetails.name,
'avatar': store.state.playerDetails.avatar
// 'avatar': constructAvatarUrl(store.state.playerDetails.avatar, 'medium')
}
SaveLastVisitedToLocalStorage(player)
setTitle(store.state.playerDetails.name)
}
const GetPlayer = async () => { const GetPlayer = async () => {
if (props.id) { if (props.id) {
const [res, resData] = await GetUser(props.id) const [res, resData] = await GetUser(props.id)
if (res === 200 && resData) { if (res === 200 && resData) {
data.playerDetails = resData store.commit({
data.tracked = resData.tracked type: 'changePlayerDetails',
data.matches = data.playerDetails.matches data: resData
data.match_stats.loss = data.playerDetails.match_stats.loss || 0 })
data.match_stats.win = data.playerDetails.match_stats.win || 0
data.match_stats.tie = data.playerDetails.match_stats.tie || 0
if (data.matches) SetPlayerData()
LoadImage(data.matches[0].map ? data.matches[0].map : 'random')
let player = { console.log(store.state.playerDetails)
'steamid64': data.playerDetails.steamid64,
'vanity_url': data.playerDetails.vanity_url || '',
'name': data.playerDetails.name,
'avatar': data.playerDetails.avatar
}
SaveLastVisitedToLocalStorage(player)
setTitle(data.playerDetails.name)
console.log(data.playerDetails)
} else { } else {
GoToLink('/') GoToLink('/')
// TODO: needs 404
} }
} else { } else {
GoToLink('/') GoToLink('/')
// TODO: needs 404
} }
} }
const TrackPlayer = async () => { const TrackPlayer = async () => {
if (data.userData.authcode !== '') { if (data.userData.authcode !== '') {
[data.statusErrorCode, data.statusError] = await TrackMe(data.playerDetails.steamid64, data.userData.authcode, data.userData.sharecode) [data.statusErrorCode, data.statusError] = await TrackMe(store.state.playerDetails.steamid64, data.userData.authcode, data.userData.sharecode)
if (data.statusErrorCode === 202) { if (data.statusErrorCode === 202) {
data.statusErrorCode = 0 data.statusErrorCode = 0
@@ -298,11 +368,22 @@ export default {
onMounted(() => { onMounted(() => {
setTimeout(() => { setTimeout(() => {
GetPlayer() if (Object.entries(store.state.playerDetails).length === 0) {
GetPlayer()
} else {
SetPlayerData()
}
}, 200) }, 200)
} }
) )
onBeforeUnmount(() => {
store.commit({
type: 'changePlayerDetails',
data: {}
})
})
return { return {
data, data,
store, store,
@@ -406,6 +487,59 @@ export default {
} }
} }
.match-container {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 1rem;
.matches {
width: 75%;
}
.side-info {
display: flex;
flex-direction: column;
gap: 1rem;
width: 25%;
height: auto;
margin-top: 30px;
.side-info-box {
width: 100%;
height: auto;
background: rgba(20, 20, 20, .8);
border: 1px solid rgba(white, .3);
border-radius: 5px;
}
.best-mate {
.heading {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
h5 {
margin: 0;
padding: 0;
}
}
hr {
margin: 0;
border-color: rgba(white, .3);
}
ul {
padding: 10px;
}
}
}
}
table { table {
margin-bottom: 0; margin-bottom: 0;
@@ -490,21 +624,10 @@ table {
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.win {
background: linear-gradient(90deg, rgba(0, 255, 0, .2) 0%, rgba(0, 255, 0, .1) 5%, var(--bs-body-bg) 30%, var(--bs-body-bg) 100%);
}
.loss {
background: linear-gradient(90deg, rgba(255, 0, 0, 0.2) 0%, rgba(255, 0, 0, 0.1) 5%, var(--bs-body-bg) 30%, var(--bs-body-bg) 100%);
}
.draw {
background: linear-gradient(90deg, rgba(255, 255, 0, 0.2) 0%, rgba(255, 255, 0, 0.1) 5%, var(--bs-body-bg) 30%, var(--bs-body-bg) 100%);
}
.card { .card {
.avatar { .avatar {
height: 75px; height: 75px !important;
width: 75px; width: 75px !important;
} }
} }
.trackme-btn { .trackme-btn {
@@ -550,4 +673,26 @@ table {
display: none; display: none;
} }
} }
@media screen and (max-width: 991px) {
.matches {
width: 100% !important;
}
.side-info {
display: none !important;
}
.avatar {
width: 100px !important;
height: 100px !important;
}
.trackme-btn {
top: 25px;
}
}
@media screen and (max-width: 1199px) {
.td-plus, .kdiff {
display: none;
}
}
</style> </style>