feat: add LMC Points column fetched from BCP league cY0LeCAPfyiG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,6 +73,7 @@
|
|||||||
<th class="w-12">#</th>
|
<th class="w-12">#</th>
|
||||||
<th class="cursor-pointer select-none" data-sort="name">Player</th>
|
<th class="cursor-pointer select-none" data-sort="name">Player</th>
|
||||||
<th class="text-right cursor-pointer select-none" data-sort="pts">ITC Points</th>
|
<th class="text-right cursor-pointer select-none" data-sort="pts">ITC Points</th>
|
||||||
|
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="lmc">LMC Points</th>
|
||||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="wlt">W–L–T</th>
|
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="wlt">W–L–T</th>
|
||||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="wpct">Win %</th>
|
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="wpct">Win %</th>
|
||||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="rank">ITC Rank</th>
|
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="rank">ITC Rank</th>
|
||||||
|
|||||||
+40
-5
@@ -43,6 +43,7 @@ const CONFIG = {
|
|||||||
teamId: "2iGDVMgX0a",
|
teamId: "2iGDVMgX0a",
|
||||||
leagueId: "BYaaUfKum7z0",
|
leagueId: "BYaaUfKum7z0",
|
||||||
regionId: "VgQKgqmTPU",
|
regionId: "VgQKgqmTPU",
|
||||||
|
lmcLeagueId: "cY0LeCAPfyiG",
|
||||||
|
|
||||||
// Fallback roster if the team endpoint requires auth.
|
// Fallback roster if the team endpoint requires auth.
|
||||||
memberIds: [],
|
memberIds: [],
|
||||||
@@ -156,6 +157,7 @@ const sortCols = {
|
|||||||
wlt: { key: r => (+r.wins||0) * 10000 - (+r.losses||0) * 100 - (+r.ties||0), defaultDir: 'desc' },
|
wlt: { key: r => (+r.wins||0) * 10000 - (+r.losses||0) * 100 - (+r.ties||0), defaultDir: 'desc' },
|
||||||
wpct: { key: r => { const g=(+r.wins||0)+(+r.losses||0)+(+r.ties||0); return g?(+r.wins||0)/g:-1; }, defaultDir: 'desc' },
|
wpct: { key: r => { const g=(+r.wins||0)+(+r.losses||0)+(+r.ties||0); return g?(+r.wins||0)/g:-1; }, defaultDir: 'desc' },
|
||||||
rank: { key: r => +(r.placing || Infinity), defaultDir: 'asc' },
|
rank: { key: r => +(r.placing || Infinity), defaultDir: 'asc' },
|
||||||
|
lmc: { key: r => { const uid = r.userId || r.user?.id; return uid && lmcPoints[uid] != null ? lmcPoints[uid] : -Infinity; }, defaultDir: 'desc' },
|
||||||
elo: { key: r => { const e = findElo(fullName(r.user || {}), r.userId || r.user?.id); return e?.elo ?? -Infinity; }, defaultDir: 'desc' },
|
elo: { key: r => { const e = findElo(fullName(r.user || {}), r.userId || r.user?.id); return e?.elo ?? -Infinity; }, defaultDir: 'desc' },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,10 +220,31 @@ async function getMemberIds(force) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- LMC Points data ---- */
|
||||||
|
const lmcPoints = {}; // userId → number
|
||||||
|
let lmcLoaded = false;
|
||||||
|
|
||||||
|
async function loadLmcData(ids) {
|
||||||
|
lmcLoaded = false;
|
||||||
|
try {
|
||||||
|
for await (const page of streamPlacings(CONFIG.lmcLeagueId)) {
|
||||||
|
for (const rec of page) {
|
||||||
|
const uid = rec.userId || rec.user?.id;
|
||||||
|
if (uid && ids.has(uid)) lmcPoints[uid] = +(rec.ITCPoints || 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('LMC data load failed:', e);
|
||||||
|
} finally {
|
||||||
|
lmcLoaded = true;
|
||||||
|
if (lastState) render(lastState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- Standings (cursor-paginated, circular-cursor safe) ---- */
|
/* ---- Standings (cursor-paginated, circular-cursor safe) ---- */
|
||||||
async function* streamPlacings() {
|
async function* streamPlacings(leagueId, regionId) {
|
||||||
const base = `${API}/placings?placingsType=player&leagueId=${CONFIG.leagueId}` +
|
let base = `${API}/placings?placingsType=player&leagueId=${leagueId}&sortAscending=false&limit=1000`;
|
||||||
`®ionId=${CONFIG.regionId}&sortAscending=false&limit=1000`;
|
if (regionId) base += `®ionId=${regionId}`;
|
||||||
|
|
||||||
let nextKey = null;
|
let nextKey = null;
|
||||||
let prevNextKey = undefined;
|
let prevNextKey = undefined;
|
||||||
@@ -325,8 +348,15 @@ function render(state) {
|
|||||||
: `<span class="block text-xs opacity-40">${fmtWpct(d.w, d.l, d.t)} career</span>`;
|
: `<span class="block text-xs opacity-40">${fmtWpct(d.w, d.l, d.t)} career</span>`;
|
||||||
const mobilePct = `<span class="block text-xs opacity-40 sm:hidden">${fmtWpct(r.wins, r.losses, r.ties)} win rate</span>`;
|
const mobilePct = `<span class="block text-xs opacity-40 sm:hidden">${fmtWpct(r.wins, r.losses, r.ties)} win rate</span>`;
|
||||||
const mobileElo = eloMatch ? `<span class="block text-xs opacity-40 sm:hidden">ELO ${Math.round(eloMatch.elo)}</span>` : '';
|
const mobileElo = eloMatch ? `<span class="block text-xs opacity-40 sm:hidden">ELO ${Math.round(eloMatch.elo)}</span>` : '';
|
||||||
|
const mobileLmc = (uid && lmcLoaded && lmcPoints[uid] != null) ? `<span class="block text-xs opacity-40 sm:hidden">LMC ${fmtPts(lmcPoints[uid])}</span>` : '';
|
||||||
|
const lmcCell = (() => {
|
||||||
|
if (!lmcLoaded) return `<td class="text-right font-mono hidden sm:table-cell"><span class="opacity-20">…</span></td>`;
|
||||||
|
const pts = uid ? lmcPoints[uid] : undefined;
|
||||||
|
return `<td class="text-right font-mono hidden sm:table-cell">${pts != null ? fmtPts(pts) : '<span class="text-base-content/40">—</span>'}</td>`;
|
||||||
|
})();
|
||||||
return `<td class="text-right font-mono font-bold">${fmtPts(r.ITCPoints)}` +
|
return `<td class="text-right font-mono font-bold">${fmtPts(r.ITCPoints)}` +
|
||||||
mobilePct + mobileElo + `</td>` +
|
mobilePct + mobileLmc + mobileElo + `</td>` +
|
||||||
|
lmcCell +
|
||||||
`<td class="text-right font-mono hidden sm:table-cell">` +
|
`<td class="text-right font-mono hidden sm:table-cell">` +
|
||||||
`<span class="text-success">${r.wins || 0}</span>–<span class="text-error">${r.losses || 0}</span>–${r.ties || 0}` +
|
`<span class="text-success">${r.wins || 0}</span>–<span class="text-error">${r.losses || 0}</span>–${r.ties || 0}` +
|
||||||
careerSub + `</td>` +
|
careerSub + `</td>` +
|
||||||
@@ -376,7 +406,11 @@ async function load(force) {
|
|||||||
const { ids, live } = await getMemberIds(force);
|
const { ids, live } = await getMemberIds(force);
|
||||||
const allRows = [];
|
const allRows = [];
|
||||||
|
|
||||||
for await (const page of streamPlacings()) {
|
// Reset and kick off LMC fetch non-blocking
|
||||||
|
Object.keys(lmcPoints).forEach(k => delete lmcPoints[k]);
|
||||||
|
loadLmcData(ids);
|
||||||
|
|
||||||
|
for await (const page of streamPlacings(CONFIG.leagueId, CONFIG.regionId)) {
|
||||||
allRows.push(...page);
|
allRows.push(...page);
|
||||||
// Render incrementally so results appear as pages arrive
|
// Render incrementally so results appear as pages arrive
|
||||||
const kept = build(allRows, ids);
|
const kept = build(allRows, ids);
|
||||||
@@ -403,6 +437,7 @@ function showSkeleton() {
|
|||||||
`<td><div class="skeleton h-4 w-5"></div></td>` +
|
`<td><div class="skeleton h-4 w-5"></div></td>` +
|
||||||
`<td><div class="skeleton h-4 w-3/5"></div><div class="skeleton h-3 w-2/5 mt-1 sm:hidden"></div></td>` +
|
`<td><div class="skeleton h-4 w-3/5"></div><div class="skeleton h-3 w-2/5 mt-1 sm:hidden"></div></td>` +
|
||||||
`<td><div class="skeleton h-4 w-12 ml-auto"></div><div class="skeleton h-3 w-10 mt-1 ml-auto sm:hidden"></div></td>` +
|
`<td><div class="skeleton h-4 w-12 ml-auto"></div><div class="skeleton h-3 w-10 mt-1 ml-auto sm:hidden"></div></td>` +
|
||||||
|
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-12 ml-auto"></div></td>` +
|
||||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-14 ml-auto"></div></td>` +
|
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-14 ml-auto"></div></td>` +
|
||||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-12 ml-auto"></div></td>` +
|
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-12 ml-auto"></div></td>` +
|
||||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-10 ml-auto"></div></td>` +
|
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-10 ml-auto"></div></td>` +
|
||||||
|
|||||||
Reference in New Issue
Block a user