Add in assets, user data loading
BIN
public/assets/card/museca.png
Normal file
|
After Width: | Height: | Size: 5.3 MiB |
BIN
public/assets/games/ddromni/card/13.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
public/assets/games/ddromni/card/14.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
public/assets/games/ddromni/card/15.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
public/assets/games/ddromni/card/16.png
Normal file
|
After Width: | Height: | Size: 616 KiB |
BIN
public/assets/games/ddromni/card/17.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
public/assets/games/ddromni/card/18.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/games/ddromni/card/19.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/assets/games/gitadora_dm/card/1.png
Normal file
|
After Width: | Height: | Size: 670 KiB |
BIN
public/assets/games/gitadora_dm/card/2.png
Normal file
|
After Width: | Height: | Size: 629 KiB |
BIN
public/assets/games/gitadora_dm/card/3.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/games/gitadora_dm/card/4.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/games/gitadora_dm/card/5.png
Normal file
|
After Width: | Height: | Size: 950 KiB |
BIN
public/assets/games/gitadora_dm/card/6.png
Normal file
|
After Width: | Height: | Size: 958 KiB |
BIN
public/assets/games/gitadora_dm/card/7.png
Normal file
|
After Width: | Height: | Size: 669 KiB |
BIN
public/assets/games/gitadora_dm/card/8.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/assets/games/gitadora_dm/card/9.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/games/gitadora_gf/card/1.png
Normal file
|
After Width: | Height: | Size: 670 KiB |
BIN
public/assets/games/gitadora_gf/card/2.png
Normal file
|
After Width: | Height: | Size: 629 KiB |
BIN
public/assets/games/gitadora_gf/card/3.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/games/gitadora_gf/card/4.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/games/gitadora_gf/card/5.png
Normal file
|
After Width: | Height: | Size: 968 KiB |
BIN
public/assets/games/gitadora_gf/card/6.png
Normal file
|
After Width: | Height: | Size: 958 KiB |
BIN
public/assets/games/gitadora_gf/card/7.png
Normal file
|
After Width: | Height: | Size: 669 KiB |
BIN
public/assets/games/gitadora_gf/card/8.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/assets/games/gitadora_gf/card/9.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/icon/museca.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 310 KiB |
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||