mirror of
https://github.com/PhaseII-eAmusement-Network/PhaseWeb3-Vue.git
synced 2026-09-12 11:15:15 -05:00
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<script setup>
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import NumberDynamic from "@/components/NumberDynamic.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import BaseLevel from "@/components/BaseLevel.vue";
|
||||
import PillTagTrend from "@/components/PillTagTrend.vue";
|
||||
import IconRounded from "@/components/IconRounded.vue";
|
||||
|
||||
defineProps({
|
||||
number: {
|
||||
@@ -34,6 +34,14 @@ defineProps({
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
iconColor: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
iconBGColor: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
trend: {
|
||||
type: String,
|
||||
default: null,
|
||||
@@ -47,35 +55,38 @@ defineProps({
|
||||
|
||||
<template>
|
||||
<CardBox>
|
||||
<BaseLevel v-if="trend" class="mb-3" mobile>
|
||||
<PillTagTrend :trend="trend" :trend-type="trendType" small />
|
||||
</BaseLevel>
|
||||
<BaseLevel mobile>
|
||||
<div>
|
||||
<h3 :class="color" class="text-lg leading-tight mb-1.5">
|
||||
{{ label }}
|
||||
</h3>
|
||||
<h1 class="text-3xl leading-tight font-semibold">
|
||||
<NumberDynamic
|
||||
v-if="number"
|
||||
:class="numColor"
|
||||
:value="number"
|
||||
:prefix="prefix"
|
||||
:suffix="suffix"
|
||||
/>
|
||||
<div :class="numColor">
|
||||
<slot />
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<BaseIcon
|
||||
<div class="flex gap-4">
|
||||
<IconRounded
|
||||
v-if="icon"
|
||||
:path="icon"
|
||||
size="48"
|
||||
w=""
|
||||
h="h-16"
|
||||
:class="color"
|
||||
:icon="icon"
|
||||
size="30"
|
||||
:class="iconColor"
|
||||
bg-color="bg-gray-800"
|
||||
/>
|
||||
</BaseLevel>
|
||||
<div>
|
||||
<BaseLevel v-if="trend" class="mb-3" mobile>
|
||||
<PillTagTrend :trend="trend" :trend-type="trendType" small />
|
||||
</BaseLevel>
|
||||
<BaseLevel mobile>
|
||||
<div>
|
||||
<h3 :class="color" class="text-lg leading-tight mb-1.5">
|
||||
{{ label }}
|
||||
</h3>
|
||||
<h1 class="text-3xl leading-tight font-semibold">
|
||||
<NumberDynamic
|
||||
v-if="number"
|
||||
:class="numColor"
|
||||
:value="number"
|
||||
:prefix="prefix"
|
||||
:suffix="suffix"
|
||||
/>
|
||||
<div :class="numColor">
|
||||
<slot />
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</BaseLevel>
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
</template>
|
||||
|
||||
@@ -6,16 +6,6 @@ export const chartColors = {
|
||||
},
|
||||
};
|
||||
|
||||
const randomChartData = (n) => {
|
||||
const data = [];
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
data.push(Math.round(Math.random() * 200));
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const datasetObject = (color, points) => {
|
||||
return {
|
||||
fill: false,
|
||||
@@ -30,21 +20,65 @@ const datasetObject = (color, points) => {
|
||||
pointHoverRadius: 4,
|
||||
pointHoverBorderWidth: 15,
|
||||
pointRadius: 4,
|
||||
data: randomChartData(points),
|
||||
data: points,
|
||||
tension: 0.5,
|
||||
cubicInterpolationMode: "default",
|
||||
label: "Plays",
|
||||
};
|
||||
};
|
||||
|
||||
export const sampleChartData = (points = 7) => {
|
||||
const labels = [];
|
||||
const parseArcadeHistory = (users) => {
|
||||
const groupByDay = (timestamps) => {
|
||||
const dayMap = {};
|
||||
timestamps.forEach((timestamp) => {
|
||||
const day = new Date(timestamp * 1000).toISOString().split("T")[0];
|
||||
dayMap[day] = (dayMap[day] || 0) + 1;
|
||||
});
|
||||
return dayMap;
|
||||
};
|
||||
|
||||
for (let i = 1; i <= points; i++) {
|
||||
labels.push(`0${i}`);
|
||||
const generateLast14Days = () => {
|
||||
const today = new Date();
|
||||
const dates = [];
|
||||
for (let i = 13; i >= 0; i--) {
|
||||
const date = new Date(today);
|
||||
date.setDate(today.getDate() - i);
|
||||
dates.push(date.toISOString().split("T")[0]); // Format: YYYY-MM-DD
|
||||
}
|
||||
return dates;
|
||||
};
|
||||
|
||||
const allTimestamps = [];
|
||||
users.forEach((user) => {
|
||||
const arcadeHistory = user.data?.arcade_history || {};
|
||||
Object.values(arcadeHistory).forEach((machines) => {
|
||||
Object.values(machines).forEach((timestamps) => {
|
||||
allTimestamps.push(...timestamps);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const playsByDay = groupByDay(allTimestamps);
|
||||
const last14Days = generateLast14Days();
|
||||
|
||||
// Populate data for the last 14 days, filling 0 for days without plays
|
||||
const playCounts = last14Days.map((day) => playsByDay[day] || 0);
|
||||
|
||||
return { labels: last14Days, data: playCounts };
|
||||
};
|
||||
|
||||
export const generateChartData = (users) => {
|
||||
if (!Array.isArray(users) || users.length === 0) {
|
||||
return {
|
||||
labels: [],
|
||||
datasets: [],
|
||||
};
|
||||
}
|
||||
|
||||
const { labels, data } = parseArcadeHistory(users);
|
||||
|
||||
return {
|
||||
labels,
|
||||
datasets: [datasetObject("info", points)],
|
||||
datasets: [datasetObject("info", data)],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,7 +23,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: "h-12",
|
||||
},
|
||||
bg: Boolean,
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: "bg-slate-900",
|
||||
},
|
||||
});
|
||||
|
||||
const spanColor = computed(() => props.iconColor);
|
||||
@@ -36,6 +39,7 @@ const spanColor = computed(() => props.iconColor);
|
||||
:h="h"
|
||||
:color="spanColor"
|
||||
size="24"
|
||||
class="rounded-full bg-slate-900"
|
||||
class="rounded-full"
|
||||
:class="props.bgColor"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -4,13 +4,19 @@ import {
|
||||
mdiGamepad,
|
||||
mdiNewspaperVariant,
|
||||
mdiChartTimelineVariant,
|
||||
mdiCounter,
|
||||
mdiGamepadOutline,
|
||||
mdiFire,
|
||||
mdiTrendingUp,
|
||||
} from "@mdi/js";
|
||||
import UserCard from "@/components/UserCard.vue";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import CardBoxWidget from "@/components/CardBoxWidget.vue";
|
||||
import CardBoxGameStat from "@/components/CardBoxGameStat.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import LineChart from "@/components/Charts/LineChart.vue";
|
||||
|
||||
import { useMainStore } from "@/stores/main";
|
||||
const mainStore = useMainStore();
|
||||
@@ -18,6 +24,7 @@ const mainStore = useMainStore();
|
||||
import CardBoxNews from "@/components/Cards/CardBoxNews.vue";
|
||||
import CardBoxComponentEmpty from "@/components/CardBoxComponentEmpty.vue";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { generateChartData } from "@/components/Charts/chart.config";
|
||||
var newsData = ref([]);
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -129,22 +136,28 @@ function filterUserProfiles(userProfiles) {
|
||||
main
|
||||
/>
|
||||
<div
|
||||
class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 3xl:grid-cols-6 mb-6"
|
||||
class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 3xl:grid-cols-5 mb-6"
|
||||
>
|
||||
<CardBoxWidget
|
||||
:icon="mdiCounter"
|
||||
:number="cumulativePlays"
|
||||
label="Cumulative Plays"
|
||||
suffix="plays"
|
||||
icon-color="text-emerald-600"
|
||||
/>
|
||||
<CardBoxWidget
|
||||
:icon="mdiGamepadOutline"
|
||||
:number="userProfiles.length"
|
||||
label="Games Played"
|
||||
suffix="games"
|
||||
icon-color="text-sky-300"
|
||||
/>
|
||||
<CardBoxWidget
|
||||
:icon="mdiFire"
|
||||
:number="longestStreak"
|
||||
label="Longest Play Streak"
|
||||
suffix="plays"
|
||||
icon-color="text-red-600"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -161,6 +174,13 @@ function filterUserProfiles(userProfiles) {
|
||||
type="plays"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SectionTitleLine :icon="mdiTrendingUp" title="Play Trends" main />
|
||||
<CardBox class="mb-6">
|
||||
<div v-if="userProfiles">
|
||||
<LineChart :data="generateChartData(userProfiles)" class="h-96" />
|
||||
</div>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user