243 lines
6.2 KiB
Svelte
243 lines
6.2 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
|
|
type Identity = {
|
|
id?: string;
|
|
name?: string;
|
|
};
|
|
|
|
type Player = {
|
|
id?: string;
|
|
name?: string;
|
|
avatar?: string | null;
|
|
country?: string | null;
|
|
role?: string | null;
|
|
rank?: number | null;
|
|
countryRank?: number | null;
|
|
techPp?: number | null;
|
|
accPp?: number | null;
|
|
passPp?: number | null;
|
|
pp?: number | null;
|
|
mapperId?: number | null;
|
|
level?: number | null;
|
|
banned?: boolean;
|
|
profileSettings?: { showAllRatings: boolean } | null;
|
|
patreon?: unknown;
|
|
};
|
|
|
|
let identity: Identity | null = null;
|
|
let player: Player | null = null;
|
|
let rawPlayer: unknown = null;
|
|
let error: string | null = null;
|
|
let loading = true;
|
|
|
|
onMount(async () => {
|
|
try {
|
|
const res = await fetch('/api/beatleader/me');
|
|
if (!res.ok) {
|
|
const body = await res.text();
|
|
throw new Error(body || `Request failed: ${res.status}`);
|
|
}
|
|
const data = (await res.json()) as { identity?: Identity; player?: Player | null; rawPlayer?: unknown };
|
|
identity = data.identity ?? null;
|
|
player = data.player ?? null;
|
|
rawPlayer = data.rawPlayer ?? null;
|
|
console.log('BeatLeader /me raw player:', rawPlayer ?? player ?? data);
|
|
} catch (err) {
|
|
error = err instanceof Error ? err.message : 'Unknown error';
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<section class="py-8">
|
|
<h1 class="font-display text-3xl sm:text-4xl">BeatLeader Testing</h1>
|
|
<p class="mt-2 text-muted text-sm">Debug view for the current BeatLeader OAuth session.</p>
|
|
|
|
{#if loading}
|
|
<div class="mt-6 text-sm text-muted">Loading player info…</div>
|
|
{:else if error}
|
|
<div class="mt-6 rounded border border-rose-500/40 bg-rose-500/10 px-4 py-3 text-rose-200 text-sm">
|
|
{error}
|
|
</div>
|
|
{:else}
|
|
<div class="mt-6 grid gap-6 lg:grid-cols-2">
|
|
<div class="card">
|
|
<h2 class="card-title">Identity</h2>
|
|
{#if identity}
|
|
<dl class="info-grid">
|
|
<div>
|
|
<dt>ID</dt>
|
|
<dd>{identity.id ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Name</dt>
|
|
<dd>{identity.name ?? '—'}</dd>
|
|
</div>
|
|
</dl>
|
|
{:else}
|
|
<p class="empty">No identity data returned.</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2 class="card-title">Player</h2>
|
|
{#if player}
|
|
<div class="player-header">
|
|
<img src={player.avatar ?? ''} alt="Avatar" class:placeholder={!player.avatar} />
|
|
<div>
|
|
<div class="player-name">{player.name ?? 'Unknown'}</div>
|
|
<div class="player-meta">
|
|
{#if player.country}
|
|
<span>{player.country}</span>
|
|
{#if player.countryRank !== null}
|
|
<span>Rank: {player.countryRank}</span>
|
|
{/if}
|
|
{/if}
|
|
{#if player.rank !== null}
|
|
<span>• Global Rank: {player.rank}</span>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<dl class="info-grid">
|
|
<div>
|
|
<dt>ID</dt>
|
|
<dd>{player.id ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Role</dt>
|
|
<dd>{player.role ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Mapper</dt>
|
|
<dd>
|
|
{#if player.mapperId}
|
|
<a class="link" href={`https://beatsaver.com/profile/${player.mapperId}`} target="_blank" rel="noreferrer">
|
|
{player.mapperId}
|
|
</a>
|
|
{:else}
|
|
—
|
|
{/if}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Level</dt>
|
|
<dd>{player.level ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>PP (Global)</dt>
|
|
<dd>{player.pp ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Tech PP</dt>
|
|
<dd>{player.techPp ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Acc PP</dt>
|
|
<dd>{player.accPp ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Pass PP</dt>
|
|
<dd>{player.passPp ?? '—'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Banned</dt>
|
|
<dd>{player.banned ? 'Yes' : 'No'}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>Show All Ratings</dt>
|
|
<dd>{player.profileSettings?.showAllRatings ? 'Enabled' : 'Disabled'}</dd>
|
|
</div>
|
|
</dl>
|
|
{:else}
|
|
<p class="empty">No player profile found for this identity.</p>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</section>
|
|
|
|
<style>
|
|
.card {
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
border-radius: 0.75rem;
|
|
padding: 1.5rem;
|
|
background: linear-gradient(160deg, rgba(15, 23, 42, 0.9), rgba(5, 9, 20, 0.92));
|
|
box-shadow: 0 20px 40px rgba(8, 14, 35, 0.35);
|
|
}
|
|
|
|
.card-title {
|
|
font-size: 1.05rem;
|
|
font-weight: 600;
|
|
color: rgba(226, 232, 240, 0.95);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.info-grid {
|
|
display: grid;
|
|
gap: 0.75rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
dt {
|
|
color: rgba(148, 163, 184, 0.75);
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
dd {
|
|
color: rgba(226, 232, 240, 0.92);
|
|
margin: 0;
|
|
}
|
|
|
|
.link {
|
|
color: rgba(34, 211, 238, 0.85);
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.player-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.player-header img {
|
|
width: 64px;
|
|
height: 64px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: 2px solid rgba(34, 211, 238, 0.35);
|
|
box-shadow: 0 0 18px rgba(34, 211, 238, 0.25);
|
|
}
|
|
|
|
.player-header img.placeholder {
|
|
opacity: 0.3;
|
|
border-style: dashed;
|
|
}
|
|
|
|
.player-name {
|
|
font-size: 1.15rem;
|
|
font-weight: 600;
|
|
color: rgba(255, 255, 255, 0.95);
|
|
}
|
|
|
|
.player-meta {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
font-size: 0.8rem;
|
|
color: rgba(148, 163, 184, 0.75);
|
|
}
|
|
|
|
.empty {
|
|
font-size: 0.85rem;
|
|
color: rgba(148, 163, 184, 0.7);
|
|
}
|
|
</style>
|
|
|