refactor(profile): data loading indicators

This commit is contained in:
2026-02-20 01:58:29 +01:00
parent 1d95b26e9c
commit 1735444176
2 changed files with 40 additions and 52 deletions
@@ -14,11 +14,14 @@
</div> </div>
<div class="history-list-box"> <div class="history-list-box">
<div v-if="combinedJournal.length == 0" class="no-recent-history text--grayed"> <Loading v-if="journalDataStatus == Status.Data.Loading" />
<div v-else-if="combinedJournal.length == 0" class="no-recent-history">
{{ t('profile.list.no-recent-history') }} {{ t('profile.list.no-recent-history') }}
</div> </div>
<router-link <router-link
v-else
v-for="entry in combinedJournal" v-for="entry in combinedJournal"
:to=" :to="
'trainNo' in entry.value 'trainNo' in entry.value
@@ -110,6 +113,8 @@ import { API } from '../../typings/api';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useApiStore } from '../../store/apiStore'; import { useApiStore } from '../../store/apiStore';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { Status } from '../../typings/common';
import Loading from '../Global/Loading.vue';
type JournalEntryType = 'Timetable' | 'Dispatcher' | 'IssuedTimetable'; type JournalEntryType = 'Timetable' | 'Dispatcher' | 'IssuedTimetable';
@@ -129,7 +134,9 @@ const { t } = useI18n();
const apiStore = useApiStore(); const apiStore = useApiStore();
const route = useRoute(); const route = useRoute();
const playerId = ref(-1);
const playerJournal = ref<API.PlayerJournal.Data | null>(null); const playerJournal = ref<API.PlayerJournal.Data | null>(null);
const journalDataStatus = ref(Status.Data.Initialized);
const activeFilterTypes = reactive<Record<JournalEntryType, boolean>>({ const activeFilterTypes = reactive<Record<JournalEntryType, boolean>>({
Timetable: true, Timetable: true,
@@ -196,21 +203,29 @@ function toggleFilter(filterType: JournalEntryType) {
} }
async function fetchPlayerJournal() { async function fetchPlayerJournal() {
const playerId = route.query.playerId?.toString(); const queryPlayerId = Number(route.query.playerId) || -1;
if (!apiStore.client || !playerId) return null; if (!apiStore.client || !queryPlayerId) return;
if (queryPlayerId != playerId.value) {
journalDataStatus.value = Status.Data.Loading;
}
playerId.value = queryPlayerId;
try { try {
const response = await apiStore.client.get<API.PlayerJournal.Data>('api/getPlayerJournal', { const response = await apiStore.client.get<API.PlayerJournal.Data>('api/getPlayerJournal', {
params: { params: {
playerId: playerId, playerId: queryPlayerId,
dateScope: '30d' dateScope: '30d'
} }
}); });
playerJournal.value = response.data; playerJournal.value = response.data;
journalDataStatus.value = Status.Data.Loaded;
} catch (error) { } catch (error) {
console.error(error); console.error(error);
journalDataStatus.value = Status.Data.Error;
} }
return null; return null;
@@ -255,6 +270,7 @@ async function fetchPlayerJournal() {
.history-list-box { .history-list-box {
padding: 0 0.5em; padding: 0 0.5em;
position: relative;
} }
.history-list-box > a { .history-list-box > a {
@@ -277,6 +293,7 @@ async function fetchPlayerJournal() {
padding: 1em; padding: 1em;
font-size: 1.25em; font-size: 1.25em;
font-weight: bold; font-weight: bold;
color: #aaa;
} }
.entry-top-date { .entry-top-date {
+19 -48
View File
@@ -9,9 +9,7 @@
</div> </div>
</div> </div>
<div v-else-if="playerDataStatus == Status.Data.Loading"> <Loading v-else-if="playerDataStatus == Status.Data.Loading" />
<Loading />
</div>
<div class="no-data-found" v-else> <div class="no-data-found" v-else>
<div> <div>
@@ -25,8 +23,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import axios from 'axios'; import axios from 'axios';
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onActivated, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router'; import { onBeforeRouteUpdate, useRoute } from 'vue-router';
import { useApiStore } from '../store/apiStore'; import { useApiStore } from '../store/apiStore';
import { API, Td2API } from '../typings/api'; import { API, Td2API } from '../typings/api';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -42,70 +40,43 @@ const { t } = useI18n();
const apiStore = useApiStore(); const apiStore = useApiStore();
const route = useRoute(); const route = useRoute();
const playerId = ref(-1);
const playerName = ref(''); const playerName = ref('');
const playerInfo = ref<API.PlayerInfo.Data | null>(null); const playerInfo = ref<API.PlayerInfo.Data | null>(null);
const playerDataStatus = ref(Status.Data.Initialized); const playerDataStatus = ref(Status.Data.Initialized);
watch( onActivated(() => {
computed(() => route.query.playerId), fetchPlayerData();
() => {
fetchAllData();
}
);
onMounted(() => {
fetchAllData();
}); });
async function fetchAllData() { async function fetchPlayerData() {
const playerId = route.query.playerId?.toString(); const queryPlayerId = Number(route.query.playerId) || -1;
playerInfo.value = null; if (!apiStore.client || !queryPlayerId) return;
playerDataStatus.value = Status.Data.Loading;
if (!playerId) { if (queryPlayerId != playerId.value) {
playerDataStatus.value = Status.Data.Loaded; playerDataStatus.value = Status.Data.Loading;
return;
} }
const playerInfoResponse = await fetchPlayerInfoData(playerId); playerId.value = queryPlayerId;
if (!playerInfoResponse) {
playerDataStatus.value = Status.Data.Loaded;
return;
}
playerName.value =
playerInfoResponse.driverStats.driverName ||
playerInfoResponse.dispatcherStats.dispatcherName ||
'';
if (!playerName.value) {
playerDataStatus.value = Status.Data.Loaded;
return;
}
playerInfo.value = playerInfoResponse;
playerDataStatus.value = Status.Data.Loaded;
}
async function fetchPlayerInfoData(playerId: string) {
if (!apiStore.client || !playerId) return null;
try { try {
const response = await apiStore.client.get<API.PlayerInfo.Data>('api/getPlayerInfo', { const response = await apiStore.client.get<API.PlayerInfo.Data>('api/getPlayerInfo', {
params: { params: {
playerId: playerId playerId: queryPlayerId
} }
}); });
return response.data; playerName.value =
response.data.driverStats.driverName || response.data.dispatcherStats.dispatcherName || '';
playerInfo.value = response.data || null;
playerDataStatus.value = Status.Data.Loaded;
} catch (error) { } catch (error) {
console.error(error); console.error(error);
playerDataStatus.value = Status.Data.Error;
} }
return null;
} }
</script> </script>