Merge pull request 'add metrics dashboard' (#20) from metrics into main
Some checks are pending
CI / Foundry project (push) Waiting to run

Reviewed-on: #20
This commit is contained in:
mic0 2024-11-06 22:19:30 +00:00
commit 88a4400307
6 changed files with 162 additions and 1 deletions

View File

@ -0,0 +1,85 @@
import { useEffect, useState } from 'react';
import styles from '../styles/Dashboard.module.css';
interface MetricsData {
totalPlayers: number;
totalRuns: number;
activePlayers24h: number;
totalBossesDefeated: number;
totalPrestigeLevelsGained: number;
}
const SUBGRAPH_URL = "https://api.studio.thegraph.com/query/75782/slay-the-moloch-base-mainnet/version/latest";
const Dashboard = () => {
const [metrics, setMetrics] = useState<MetricsData>();
useEffect(() => {
const fetchMetrics = async () => {
try {
const response = await fetch(SUBGRAPH_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `{
# Get global stats
globalStat(id: "1") {
totalPlayers
totalBossesDefeated
totalPrestigeLevels
totalRuns
}
# Get active players in last 24h
players(where: { lastRaidedAt_gt: "${Math.floor(Date.now() / 1000) - 86400}" }) {
id
}
}`
})
});
const data = await response.json();
setMetrics({
totalPlayers: parseInt(data.data.globalStat.totalPlayers),
totalRuns: parseInt(data.data.globalStat.totalRuns),
activePlayers24h: data.data.players.length,
totalBossesDefeated: parseInt(data.data.globalStat.totalBossesDefeated),
totalPrestigeLevels: parseInt(data.data.globalStat.totalPrestigeLevels)
});
} catch (error) {
console.error("Error fetching metrics:", error);
}
};
fetchMetrics();
const interval = setInterval(fetchMetrics, 30000); // Refresh every 30 seconds
return () => clearInterval(interval);
}, []);
return (
<div className={styles.dashboard}>
<div className={styles.metric}>
<h3>Total Players</h3>
<p>{metrics?.totalPlayers || 0}</p>
</div>
<div className={styles.metric}>
<h3>Total Game Runs</h3>
<p>{metrics?.totalRuns || 0}</p>
</div>
<div className={styles.metric}>
<h3>Active Players (24h)</h3>
<p>{metrics?.activePlayers24h || 0}</p>
</div>
<div className={styles.metric}>
<h3>Total Bosses Defeated</h3>
<p>{metrics?.totalBossesDefeated || 0}</p>
</div>
<div className={styles.metric}>
<h3>Total Prestige Levels</h3>
<p>{metrics?.totalPrestigeLevels || 0}</p>
</div>
</div>
);
};
export default Dashboard;

View File

@ -8,6 +8,7 @@ import Leaderboard from "./Leaderboard";
import { usePlayer } from "../providers/PlayerProvider"; import { usePlayer } from "../providers/PlayerProvider";
import Boss from "./Boss"; import Boss from "./Boss";
import BossInfo from "./BossInfo"; import BossInfo from "./BossInfo";
import Link from "next/link";
const bossToMountainsClass = { const bossToMountainsClass = {
0: styles.mountains0, 0: styles.mountains0,
@ -53,6 +54,7 @@ const Scene = () => {
> >
🏆 <span className={styles.hideMobile}>Top players</span> 🏆 <span className={styles.hideMobile}>Top players</span>
</button> </button>
<Link href="/metrics" className={styles.metricsButton}>📈 <span className={styles.hideMobile}>Game metrics</span></Link>
{isLeaderboardOpen && ( {isLeaderboardOpen && (
<div className={styles.leaderboardOverlay}> <div className={styles.leaderboardOverlay}>
<div className={styles.leaderboardContent}> <div className={styles.leaderboardContent}>

15
app/src/pages/metrics.tsx Normal file
View File

@ -0,0 +1,15 @@
import Dashboard from '../components/Dashboard';
import styles from '../styles/Metrics.module.css';
import Link from 'next/link';
const MetricsPage = () => {
return (
<div className={styles.metricsPage}>
<Link href="/" className={styles.backLink}> Back to game</Link>
<h1>Game Metrics</h1>
<Dashboard />
</div>
);
};
export default MetricsPage;

View File

@ -402,7 +402,8 @@
} }
} }
.leaderboardButton { .leaderboardButton,
.metricsButton {
position: absolute; position: absolute;
top: 30px; top: 30px;
left: 80px; left: 80px;
@ -425,6 +426,12 @@
} }
} }
} }
.metricsButton {
left: auto;
top: auto;
right: 32px;
bottom: 32px;
}
.leaderboardButton:hover { .leaderboardButton:hover {
transform: scale(1.1); transform: scale(1.1);

View File

@ -0,0 +1,29 @@
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.metric {
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
padding: 1.5rem;
text-align: center;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.metric h3 {
color: #888;
margin: 0 0 1rem 0;
font-size: 1.1rem;
}
.metric p {
color: #fff;
font-size: 2rem;
margin: 0;
font-weight: bold;
}

View File

@ -0,0 +1,23 @@
.metricsPage {
min-height: 100vh;
padding: 2rem;
background: #1a1a1a;
color: white;
}
.metricsPage h1 {
text-align: center;
margin-bottom: 3rem;
}
.backLink {
display: inline-block;
color: #888;
text-decoration: none;
margin-bottom: 2rem;
transition: color 0.2s;
}
.backLink:hover {
color: white;
}