Add in assets, user data loading

This commit is contained in:
Trenton Zimmer 2024-06-14 18:21:02 -04:00
parent 4ee1345583
commit badaee3271
33 changed files with 205 additions and 134 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 310 KiB

View File

@ -26,13 +26,10 @@ const props = defineProps({
});
function colorText() {
if (props.profile.stats) {
const stats = props.profile.stats;
if (stats.jubility) {
return getJubilityColor(stats.jubility);
} else if (stats.skillPoints) {
return getGitadoraColor(stats.skillPoints);
}
if (props.profile.jubility) {
return getJubilityColor(props.profile.jubility);
} else if (props.profile.records) {
return getGitadoraColor(props.profile.records.skill);
}
}
@ -44,7 +41,7 @@ const thisGame = getGameInfo(props.game);
<!-- <img v-if="profile.avatar" class="h-40" :src="profile.avatar" /> -->
<div class="grid grid-cols-1 text-center">
<h1 :class="colorText()" class="text-4xl md:text-5xl font-bold">
{{ profile.name }}
{{ profile.username }}
</h1>
<p class="text-xl font-mono">{{ dashCode(profile.extid) }}</p>
</div>

View File

@ -214,6 +214,7 @@ export class VersionConstants {
static POPN_MUSIC_USANEKO = 24;
static POPN_MUSIC_PEACE = 25;
static POPN_MUSIC_KAIMEI_RIDDLES = 26;
static POPN_MUSIC_UNILAB = 27;
static QMA = 1;
static QMA_II = 2;
@ -350,6 +351,7 @@ export const gameData = [
noRivals: true,
noScores: true,
noRecords: true,
skip: true,
playerHeaders: [
{ text: "Region", value: "region", sortable: true, width: 100 },
{ text: "Home Arcade", value: "homeArcade", sortable: true, width: 150 },
@ -373,6 +375,7 @@ export const gameData = [
noRivals: true,
noScores: true,
noRecords: true,
skip: true,
},
{
id: GameConstants.DANCE_RUSH,
@ -1229,6 +1232,7 @@ export const gameData = [
noRivals: true,
noScores: true,
noRecords: true,
skip: true,
playerHeaders: [
{ text: "Girlfriend", value: "gf", sortable: true, width: 100 },
],
@ -1446,6 +1450,10 @@ export const gameData = [
id: VersionConstants.POPN_MUSIC_KAIMEI_RIDDLES,
label: "解明リドルズ (Kaimei riddles)",
},
{
id: VersionConstants.POPN_MUSIC_UNILAB,
label: "UniLab",
},
],
},
{

View File

@ -5,6 +5,7 @@ import { loadUserAuthKey, saveUserAuthKey } from "@/stores/auth";
export const useMainStore = defineStore("main", {
state: () => ({
/* User */
userId: null,
userName: null,
userEmail: null,
userAvatar: null,
@ -31,6 +32,9 @@ export const useMainStore = defineStore("main", {
}),
actions: {
setUser(payload) {
if (payload.id) {
this.userId = payload.id;
}
if (payload.name) {
this.userName = payload.name;
}
@ -202,6 +206,7 @@ export const useMainStore = defineStore("main", {
const response = await this.callApi(`/user/${userId}`);
var user = response.user;
this.setUser({
id: userId,
name: user.name,
email: user.email,
avatar: user.avatar,
@ -264,5 +269,31 @@ export const useMainStore = defineStore("main", {
throw error;
}
},
async getGameProfiles(game) {
try {
const data = await this.callApi(`/game/${game}/profiles`);
return data.data;
} catch (error) {
console.log("Error fetching profiles:", error);
throw error;
}
},
async getUserProfile(game, version) {
while (!this.userId) {
await new Promise((resolve) => setTimeout(resolve, 200)); // Wait for 100 milliseconds
}
try {
const data = await this.callApi(
`/profile/${game}?version=${version}&userId=${this.userId}`
);
return data.data;
} catch (error) {
console.log("Error fetching profile:", error);
throw error;
}
},
},
});

View File

@ -1,5 +1,5 @@
<script setup>
import { reactive } from "vue";
import { reactive, ref, onMounted, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import {
mdiAccountMultiple,
@ -7,7 +7,6 @@ import {
mdiFormatListText,
} from "@mdi/js";
import { useMainStore } from "@/stores/main";
import { onMounted } from "vue";
import SectionMain from "@/components/SectionMain.vue";
import BaseButton from "@/components/BaseButton.vue";
import SectionTitleLine from "@/components/SectionTitleLine.vue";
@ -32,28 +31,12 @@ const versionForm = reactive({
currentVersion: null,
});
var profile = {
id: 1,
name: "Trmazi",
extid: 12345678,
avatar:
"https://static.wikia.nocookie.net/dancedancerevolutionddr/images/3/3b/Yuni_img1.gif/",
last: {
arcade: "GhettoCade",
date: "7/16/2023",
},
stats: {
firstPlay: "1/14/2021",
singlePlays: 165,
singleDan: 1900,
singlePoint: 1877,
doublePlays: 15,
doubleDan: 0,
doublePoint: 187,
skillPoints: 3723,
jubility: 7690,
},
};
watch(
() => versionForm.currentVersion,
() => {
loadProfile();
}
);
gameID = $route.params.id;
thisGame = getGameInfo(gameID);
@ -67,89 +50,39 @@ if (thisGame == null) {
});
}
const headers = [];
headers.push({
text: "Player",
value: "username",
sortable: true,
width: 120,
const myProfile = ref(null);
const profiles = ref([]);
onMounted(async () => {
try {
const data = await mainStore.getGameProfiles(gameID);
profiles.value = formatProfiles(data);
} catch (error) {
console.error("Failed to fetch profile data:", error);
}
loadProfile();
});
if (!thisGame.noRivals) {
headers.push({ text: "Rival ID", value: "extid", width: 100 });
}
headers.push(
{ text: "Plays", value: "plays", sortable: true, width: 50 },
{ text: "Last Arcade", value: "last.arcade", sortable: true, width: 150 }
);
if (thisGame.playerHeaders) {
for (var header of thisGame.playerHeaders) {
headers.push(header);
}
}
const items = [
{
username: "Trmazi",
extid: 12345678,
plays: 30,
last: { arcade: "Ghettocade" },
sp: { dan: 100, point: 2001 },
dp: { dan: 200, point: 3000 },
},
{
username: "Trmazi",
extid: 12345678,
plays: 31,
last: { arcade: "Ghettocade" },
sp: { dan: 1900, point: 2000 },
dp: { dan: 1200, point: 3000 },
},
{
username: "Trmazi",
extid: 12345678,
plays: 32,
last: { arcade: "Ghettocade" },
sp: { dan: 800, point: 2000 },
dp: { dan: 900, point: 3000 },
},
];
var formattedItems = [];
for (var item of items) {
if (item.extid) {
item.extid = dashCode(item.extid);
}
if (item.sp) {
if (item.sp.dan !== undefined) {
item.sp.dan = getIIDXDan(item.sp.dan).short;
}
}
if (item.dp) {
if (item.dp.dan !== undefined) {
item.dp.dan = getIIDXDan(item.dp.dan).short;
}
}
formattedItems.push(item);
}
if (!thisGame.versions) {
versionForm.currentVersion = 1;
}
var userVersions = {};
onMounted(() => {
userVersions = mainStore.profiles[gameID];
console.log(userVersions);
if (userVersions != undefined) {
versionForm.currentVersion = Math.max(...userVersions);
async function loadProfile() {
try {
const data = await mainStore.getUserProfile(
gameID,
versionForm.currentVersion
);
myProfile.value = data;
if (data && !versionForm.currentVersion) {
versionForm.currentVersion = data.versions[data.versions.length - 1];
}
} catch (error) {
console.error("Failed to fetch user profile data:", error);
}
});
}
function getSources() {
var sources = null;
@ -168,6 +101,77 @@ function getCardStyle() {
background-repeat: no-repeat;
`;
}
const headers = [];
headers.push({
text: "Player",
value: "username",
sortable: true,
width: 120,
});
if (!thisGame.noRivals) {
headers.push({ text: "Rival ID", value: "extid", width: 100 });
}
headers.push(
{ text: "Last Play", value: "stats.last_play_timestamp", width: 150 },
{ text: "Plays", value: "stats.total_plays", sortable: true, width: 50 }
// { text: "Last Arcade", value: "last.arcade", sortable: true, width: 150 }
);
if (thisGame.playerHeaders) {
for (var header of thisGame.playerHeaders) {
headers.push(header);
}
}
function formatProfiles(profiles) {
var formattedItems = [];
for (var item of profiles) {
if (item.extid) {
item.extid = dashCode(item.extid);
}
if (item.stats) {
if (item.stats.last_play_timestamp) {
const date = new Date(item.stats.last_play_timestamp * 1000);
item.stats.last_play_timestamp = date.toLocaleString();
}
if (item.sp) {
if (item.sp.dan !== undefined) {
item.sp.dan = getIIDXDan(item.sp.dan).short;
}
}
if (item.dp) {
if (item.dp.dan !== undefined) {
item.dp.dan = getIIDXDan(item.dp.dan).short;
}
}
}
formattedItems.push(item);
}
formattedItems.sort((a, b) => {
const totalPlaysA = a.stats ? a.stats.total_plays || 0 : 0;
const totalPlaysB = b.stats ? b.stats.total_plays || 0 : 0;
return totalPlaysB - totalPlaysA; // Sort in descending order
});
return formattedItems;
}
function filterVersions(haveVersions) {
var filtered = [];
for (const version of thisGame.versions) {
if (haveVersions.includes(version.id)) {
filtered.push(version);
}
}
return filtered;
}
</script>
<template>
@ -181,11 +185,7 @@ function getCardStyle() {
>
<GameTitleLine :path="thisGame.icon" :title="thisGame.name" />
<div
v-if="
thisGame.versions &&
userVersions &&
gameID in mainStore.profiles
"
v-if="thisGame.versions && myProfile"
class="md:w-1/3 md:text-right"
>
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
@ -193,17 +193,28 @@ function getCardStyle() {
</h2>
<FormControl
v-model="versionForm.currentVersion"
:options="thisGame.versions"
:options="filterVersions(myProfile.versions)"
/>
</div>
</div>
</div>
<div v-if="gameID in mainStore.profiles" class="w-full pt-6">
<ProfileCard :game="gameID" :profile="profile">
<div v-if="myProfile" class="w-full pt-6">
<ProfileCard :game="gameID" :profile="myProfile">
<div class="grid grid-cols-2 gap-6 pt-6">
<CardBoxWidget :number="3733" label="Scores" />
<CardBoxWidget :number="1244" label="Plays" /></div
></ProfileCard>
<CardBoxWidget
:number="myProfile.stats.total_plays"
label="Plays"
/>
<template v-if="myProfile.records">
<CardBoxWidget
v-if="myProfile.records.skill"
:number="myProfile.records.skill"
label="Skill Points"
/>
</template>
</div>
</ProfileCard>
</div>
<div v-else class="md:w-1/2 grid grid-cols-1 md:grid-cols-2 gap-3">
<BaseButton
@ -232,7 +243,7 @@ function getCardStyle() {
class="bg-white dark:bg-slate-900/95 rounded-2xl lg:flex lg:justify-between"
>
<div class="w-full">
<GeneralTable :headers="headers" :items="formattedItems" />
<GeneralTable :headers="headers" :items="profiles" />
</div>
</div>
</CardBox>

View File

@ -1,17 +1,19 @@
<script setup>
import { ref, onMounted, watch } from "vue";
import { computed, ref, onMounted, watch } from "vue";
import {
// mdiReload,
// mdiChartBellCurveCumulative,
mdiGamepad,
// mdiTestTube,
mdiNewspaperVariant,
mdiChartTimelineVariant,
} from "@mdi/js";
import UserCard from "@/components/UserCard.vue";
import * as chartConfig from "@/components/Charts/chart.config.js";
// import LineChart from "@/components/Charts/LineChart.vue";
import SectionMain from "@/components/SectionMain.vue";
// import CardBox from "@/components/CardBox.vue";
//import CardBox from "@/components/CardBox.vue";
import CardBoxWidget from "@/components/CardBoxWidget.vue";
// import BaseButton from "@/components/BaseButton.vue";
import CardBoxGameStat from "@/components/CardBoxGameStat.vue";
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
@ -21,6 +23,7 @@ import SectionTitleLine from "@/components/SectionTitleLine.vue";
// Public beta news data
import CardBoxNews from "@/components/Cards/CardBoxNews.vue";
import CardBoxComponentEmpty from "@/components/CardBoxComponentEmpty.vue";
import { getGameInfo } from "@/constants";
import { useMainStore } from "@/stores/main";
const mainStore = useMainStore();
var newsData = ref([]);
@ -70,6 +73,30 @@ watch(
userProfiles.value = newValue;
}
);
const cumulativePlays = computed(() => {
return userProfiles.value.reduce(
(total, user) => total + user.data.total_plays,
0
);
});
// const sortedUserProfiles = computed(() => {
// return [...userProfiles.value].sort(
// (a, b) => b.data.last_play_timestamp - a.data.last_play_timestamp
// );
// });
function filterUserProfiles(userProfiles) {
var filteredProfiles = [];
for (const profile of userProfiles) {
const game = getGameInfo(profile.game);
if (game && !game.skip) {
filteredProfiles.push(profile);
}
}
return filteredProfiles;
}
</script>
<template>
@ -104,27 +131,24 @@ watch(
</NotificationBar>
</div> -->
<!-- This is for tracking stats. -->
<!-- <SectionTitleLine
<SectionTitleLine
:icon="mdiChartTimelineVariant"
title="Quick Stats"
main
/> -->
<!-- <div class="grid grid-cols-1 gap-6 lg:grid-cols-3 mb-6">
<CardBoxWidget
trend="12% (from last week)"
trend-type="up"
:number="37"
label="Scores (This week)"
/>
</div> -->
/>
<div
class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 mb-6"
>
<CardBoxWidget :number="cumulativePlays" label="Cumulative Plays" />
<CardBoxWidget :number="userProfiles.length" label="Games Played" />
</div>
<SectionTitleLine :icon="mdiGamepad" title="Showcase" main />
<div
class="grid grid-flow-row auto-rows-auto grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5 mb-5"
>
<CardBoxGameStat
v-for="profile of userProfiles"
v-for="profile of filterUserProfiles(userProfiles)"
:key="profile.game"
:game="profile.game"
:value="profile.data.total_plays"