mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
refactor(profile): moved fetching data to view root to ensure proper loading on activating
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
|
||||
<div class="history-list-box">
|
||||
<Loading v-if="journalDataStatus == Status.Data.Loading" />
|
||||
<Loading v-if="journalStatus == Status.Data.Loading" />
|
||||
|
||||
<div v-else-if="combinedJournal.length == 0" class="no-recent-history">
|
||||
{{ t('profile.list.no-recent-history') }}
|
||||
@@ -107,12 +107,21 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onActivated, onDeactivated, onMounted, reactive, ref } from 'vue';
|
||||
import {
|
||||
computed,
|
||||
onActivated,
|
||||
onDeactivated,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
PropType,
|
||||
reactive,
|
||||
ref
|
||||
} from 'vue';
|
||||
import { dateToLocaleString, humanizeDuration } from '../../composables/time';
|
||||
import { API } from '../../typings/api';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useApiStore } from '../../store/apiStore';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { onBeforeRouteUpdate, useRoute } from 'vue-router';
|
||||
import { Status } from '../../typings/common';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
|
||||
@@ -127,18 +136,19 @@ interface JournalEntry {
|
||||
const props = defineProps({
|
||||
playerName: {
|
||||
type: String
|
||||
},
|
||||
|
||||
playerJournal: {
|
||||
type: Object as PropType<API.PlayerJournal.Data>,
|
||||
},
|
||||
|
||||
journalStatus: {
|
||||
type: Number as PropType<Status.Data>,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
const apiStore = useApiStore();
|
||||
const route = useRoute();
|
||||
|
||||
const playerId = ref(-1);
|
||||
const playerJournal = ref<API.PlayerJournal.Data | null>(null);
|
||||
const journalDataStatus = ref(Status.Data.Initialized);
|
||||
|
||||
const intervalId = ref(-1);
|
||||
|
||||
const activeFilterTypes = reactive<Record<JournalEntryType, boolean>>({
|
||||
Timetable: true,
|
||||
@@ -146,23 +156,13 @@ const activeFilterTypes = reactive<Record<JournalEntryType, boolean>>({
|
||||
IssuedTimetable: true
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
fetchPlayerJournal();
|
||||
intervalId.value = setInterval(fetchPlayerJournal, 30000);
|
||||
});
|
||||
|
||||
onDeactivated(() => {
|
||||
clearInterval(intervalId.value);
|
||||
intervalId.value = -1;
|
||||
});
|
||||
|
||||
const combinedJournal = computed<JournalEntry[]>(() => {
|
||||
if (!playerJournal.value || !props.playerName) return [];
|
||||
if (!props.playerJournal || !props.playerName) return [];
|
||||
|
||||
const list = [
|
||||
...playerJournal.value.timetables,
|
||||
...playerJournal.value.duties,
|
||||
...playerJournal.value.issuedTimetables
|
||||
...props.playerJournal.timetables,
|
||||
...props.playerJournal.duties,
|
||||
...props.playerJournal.issuedTimetables
|
||||
]
|
||||
.reduce<JournalEntry[]>((acc, v) => {
|
||||
// Timetable or dispatcher type
|
||||
@@ -209,35 +209,6 @@ function toggleFilter(filterType: JournalEntryType) {
|
||||
|
||||
activeFilterTypes[filterType] = toggledState;
|
||||
}
|
||||
|
||||
async function fetchPlayerJournal() {
|
||||
const queryPlayerId = Number(route.query.playerId) || -1;
|
||||
|
||||
if (!apiStore.client || !queryPlayerId) return;
|
||||
|
||||
if (queryPlayerId != playerId.value) {
|
||||
journalDataStatus.value = Status.Data.Loading;
|
||||
}
|
||||
|
||||
playerId.value = queryPlayerId;
|
||||
|
||||
try {
|
||||
const response = await apiStore.client.get<API.PlayerJournal.Data>('api/getPlayerJournal', {
|
||||
params: {
|
||||
playerId: queryPlayerId,
|
||||
dateScope: '30d'
|
||||
}
|
||||
});
|
||||
|
||||
playerJournal.value = response.data;
|
||||
journalDataStatus.value = Status.Data.Loaded;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
journalDataStatus.value = Status.Data.Error;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<router-link
|
||||
v-for="d in activeDispatches"
|
||||
class="dispatcher-badge"
|
||||
:to="`/scenery?station=${d.stationName}`"
|
||||
:to="`/scenery?station=${d.stationName}®ion=${d.region}`"
|
||||
>
|
||||
<img src="/images/icon-user.svg" width="25" alt="user icon" />
|
||||
<b>{{ d.stationName }} ({{ getRegionNameById(d.region) }})</b>
|
||||
@@ -88,17 +88,17 @@
|
||||
|
||||
<div class="info-activity" v-if="activeTrains.length > 0">
|
||||
<router-link
|
||||
v-for="d in activeTrains"
|
||||
:to="`/driver?trainId=${d.id}`"
|
||||
v-for="t in activeTrains"
|
||||
:to="`/driver?trainId=${t.id}`"
|
||||
class="driver-badge"
|
||||
>
|
||||
<img src="/images/icon-train.svg" width="25" alt="train icon" />
|
||||
<span v-if="d.timetable" class="text--primary">{{ d.timetable.category }}</span>
|
||||
<span>{{ d.trainNo }}</span>
|
||||
<span v-if="t.timetable" class="text--primary">{{ t.timetable.category }}</span>
|
||||
<span>{{ t.trainNo }}</span>
|
||||
•
|
||||
<span>{{ d.currentStationName }} ({{ getRegionNameById(d.region) }})</span>
|
||||
<span>{{ t.currentStationName }} ({{ getRegionNameById(t.region) }})</span>
|
||||
•
|
||||
<span class="text--grayed">{{ d.stockString.split(';')[0] }}</span>
|
||||
<span class="text--grayed">{{ t.stockString.split(';')[0] }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -221,7 +221,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, PropType, ref } from 'vue';
|
||||
import { computed, onActivated, onMounted, PropType, ref, watch } from 'vue';
|
||||
import { API, Td2API } from '../../typings/api';
|
||||
import { calculateExpStyles } from '../../composables/badge';
|
||||
import { getCountPercentage } from '../../utils/calcUtils';
|
||||
@@ -245,28 +245,26 @@ const props = defineProps({
|
||||
required: true
|
||||
},
|
||||
|
||||
playerTD2Info: {
|
||||
type: Object as PropType<Td2API.UsersInfoByName.UserInfo>
|
||||
},
|
||||
|
||||
playerName: {
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const playerTD2Info = ref<Td2API.UsersInfoByName.UserInfo | null>(null);
|
||||
|
||||
const isPlayerDonator = computed(() =>
|
||||
props.playerName ? apiStore.donatorsData.includes(props.playerName) : false
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
fetchTD2Data();
|
||||
});
|
||||
|
||||
const activeDispatches = computed(() => {
|
||||
if (!props.playerName) return [];
|
||||
if (!apiStore.activeData || !apiStore.activeData.activeSceneries) return [];
|
||||
|
||||
return apiStore.activeData.activeSceneries.filter(
|
||||
(sc) =>
|
||||
sc.dispatcherName == props.playerName && (sc.lastSeen >= Date.now() - 60000 || sc.isOnline)
|
||||
sc.dispatcherName == props.playerName && (sc.lastSeen <= Date.now() - 60000 || sc.isOnline)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -275,30 +273,9 @@ const activeTrains = computed(() => {
|
||||
if (!apiStore.activeData || !apiStore.activeData.trains) return [];
|
||||
|
||||
return apiStore.activeData.trains.filter(
|
||||
(t) => t.driverName == props.playerName && (t.lastSeen >= Date.now() - 60000 || t.online)
|
||||
(t) => t.driverName == props.playerName && (t.lastSeen <= Date.now() - 60000 || t.online)
|
||||
);
|
||||
});
|
||||
|
||||
async function fetchTD2Data() {
|
||||
if (!props.playerName) return;
|
||||
|
||||
try {
|
||||
const response = await axios.get<Td2API.UsersInfoByName.Response>('https://api.td2.info.pl', {
|
||||
params: {
|
||||
method: 'getUsersInfoByName',
|
||||
name: props.playerName
|
||||
}
|
||||
});
|
||||
|
||||
if (response.data.success && response.data.message.length == 1) {
|
||||
playerTD2Info.value = response.data.message[0];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -74,7 +74,6 @@ const routes: Array<RouteRecordRaw> = [
|
||||
|
||||
const router = createRouter({
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
console.log(to.name);
|
||||
if (
|
||||
(to.name == 'SceneryView' || to.name == 'DriverView' || to.name == 'PlayerProfileView') &&
|
||||
from.name !== to.name &&
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
<template>
|
||||
<div class="profile-view">
|
||||
<div class="profile-wrapper" v-if="playerInfo && playerDataStatus == Status.Data.Loaded">
|
||||
<ProfileSummary :playerInfo="playerInfo" :playerName="playerName" />
|
||||
<div class="profile-wrapper" v-if="playerInfo && playerInfoStatus == Status.Data.Loaded">
|
||||
<ProfileSummary
|
||||
:playerInfo="playerInfo"
|
||||
:playerTD2Info="playerTD2Info"
|
||||
:playerName="playerName"
|
||||
/>
|
||||
|
||||
<div class="profile-side">
|
||||
<ProfileRecentStats :playerInfo="playerInfo" />
|
||||
<ProfileHistoryList :playerName="playerName" />
|
||||
<ProfileHistoryList
|
||||
:playerName="playerName"
|
||||
:playerJournal="playerJournal"
|
||||
:journalStatus="playerJournalStatus"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Loading v-else-if="playerDataStatus == Status.Data.Loading" />
|
||||
<Loading v-else-if="playerInfoStatus == Status.Data.Loading" />
|
||||
|
||||
<div class="no-data-found" v-else>
|
||||
<div>
|
||||
@@ -22,9 +30,9 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated, onDeactivated, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { onBeforeRouteUpdate, useRoute } from 'vue-router';
|
||||
import { useApiStore } from '../store/apiStore';
|
||||
import { API } from '../typings/api';
|
||||
import { API, Td2API } from '../typings/api';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Status } from '../typings/common';
|
||||
|
||||
@@ -32,6 +40,7 @@ import Loading from '../components/Global/Loading.vue';
|
||||
import ProfileSummary from '../components/PlayerProfileView/ProfileSummary.vue';
|
||||
import ProfileRecentStats from '../components/PlayerProfileView/ProfileRecentStats.vue';
|
||||
import ProfileHistoryList from '../components/PlayerProfileView/ProfileHistoryList.vue';
|
||||
import axios from 'axios';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -41,8 +50,12 @@ const route = useRoute();
|
||||
const playerId = ref(-1);
|
||||
const playerName = ref('');
|
||||
|
||||
const playerInfo = ref<API.PlayerInfo.Data | null>(null);
|
||||
const playerDataStatus = ref(Status.Data.Initialized);
|
||||
const playerInfo = ref<API.PlayerInfo.Data | undefined>(undefined);
|
||||
const playerTD2Info = ref<Td2API.UsersInfoByName.UserInfo | undefined>(undefined);
|
||||
const playerJournal = ref<API.PlayerJournal.Data | undefined>(undefined);
|
||||
|
||||
const playerInfoStatus = ref(Status.Data.Initialized);
|
||||
const playerJournalStatus = ref(Status.Data.Initialized);
|
||||
|
||||
const intervalId = ref(-1);
|
||||
|
||||
@@ -57,32 +70,76 @@ onDeactivated(() => {
|
||||
intervalId.value = -1;
|
||||
});
|
||||
|
||||
async function fetchPlayerInfo(playerId: number) {
|
||||
return apiStore.client!.get<API.PlayerInfo.Data>('api/getPlayerInfo', {
|
||||
params: {
|
||||
playerId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchPlayerJournal(playerId: number) {
|
||||
return apiStore.client!.get<API.PlayerJournal.Data>('api/getPlayerJournal', {
|
||||
params: {
|
||||
playerId,
|
||||
dateScope: '30d'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchPlayerTd2Info(playerName: string) {
|
||||
return axios.get<Td2API.UsersInfoByName.Response>('https://api.td2.info.pl', {
|
||||
params: {
|
||||
method: 'getUsersInfoByName',
|
||||
name: playerName
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchPlayerData() {
|
||||
const queryPlayerId = Number(route.query.playerId) || -1;
|
||||
|
||||
if (!apiStore.client || !queryPlayerId) return;
|
||||
|
||||
if (queryPlayerId != playerId.value) {
|
||||
playerDataStatus.value = Status.Data.Loading;
|
||||
playerInfoStatus.value = Status.Data.Loading;
|
||||
playerJournalStatus.value = Status.Data.Loading;
|
||||
}
|
||||
|
||||
playerId.value = queryPlayerId;
|
||||
|
||||
try {
|
||||
const response = await apiStore.client.get<API.PlayerInfo.Data>('api/getPlayerInfo', {
|
||||
params: {
|
||||
playerId: queryPlayerId
|
||||
}
|
||||
});
|
||||
const playerInfoResp = await fetchPlayerInfo(playerId.value);
|
||||
|
||||
playerName.value =
|
||||
response.data.driverStats.driverName || response.data.dispatcherStats.dispatcherName || '';
|
||||
playerInfoResp.data.driverStats.driverName ||
|
||||
playerInfoResp.data.dispatcherStats.dispatcherName ||
|
||||
'';
|
||||
|
||||
playerInfo.value = response.data || null;
|
||||
playerDataStatus.value = Status.Data.Loaded;
|
||||
playerInfo.value = playerInfoResp.data;
|
||||
playerInfoStatus.value = Status.Data.Loaded;
|
||||
|
||||
if (playerName.value) {
|
||||
const playerTD2InfoResp = await fetchPlayerTd2Info(playerName.value);
|
||||
|
||||
if (playerTD2InfoResp.data.success && playerTD2InfoResp.data.message.length == 1) {
|
||||
playerTD2Info.value = playerTD2InfoResp.data.message[0];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
playerDataStatus.value = Status.Data.Error;
|
||||
playerInfo.value = undefined;
|
||||
playerTD2Info.value = undefined;
|
||||
playerInfoStatus.value = Status.Data.Error;
|
||||
}
|
||||
|
||||
try {
|
||||
const playerJournalResp = await fetchPlayerJournal(playerId.value);
|
||||
|
||||
playerJournal.value = playerJournalResp.data;
|
||||
playerJournalStatus.value = Status.Data.Loaded;
|
||||
} catch (error) {
|
||||
playerJournal.value = undefined;
|
||||
playerJournalStatus.value = Status.Data.Error;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user