Module:PlayerDashboard
From eSportsAmaze
More actions
Documentation for this module may be created at Module:PlayerDashboard/doc
-- Module:PlayerDashboard
-- Full-width player dashboard. Reads all data from existing Cargo tables.
-- No changes to any existing module or template needed.
local p = {}
local cargo = mw.ext.cargo
local html = mw.html
local lang = mw.getContentLanguage()
local function esc(s)
if not s then return "" end
return s:gsub("\\","\\\\"):gsub("'","\\'")
end
local function fmtCurrency(n)
if not n or n == 0 then return "—" end
local s = tostring(math.floor(n))
local l3 = s:sub(-3)
local rest = s:sub(1,-4)
local fmt = rest:reverse():gsub("(%d%d)","%1,"):reverse()
if fmt ~= "" then l3 = "," .. l3 end
return "₹ " .. fmt .. l3
end
local function fmtDate(d)
if not d or d == "" then return "?" end
return lang:formatDate("M y", d)
end
local function statusColor(s)
s = (s or ""):lower()
if s == "active" then return "#22c55e", "rgba(34,197,94,.15)", "rgba(34,197,94,.3)" end
if s == "inactive" then return "#f59e0b", "rgba(245,158,11,.15)", "rgba(245,158,11,.3)" end
if s == "retired" then return "#94a3b8", "rgba(148,163,184,.15)","rgba(148,163,184,.3)"end
if s == "banned" then return "#ef4444", "rgba(239,68,68,.15)", "rgba(239,68,68,.3)" end
return "#94a3b8", "rgba(148,163,184,.15)", "rgba(148,163,184,.3)"
end
function p.main(frame)
local pageName = mw.title.getCurrentTitle().text
local sqlPage = esc(pageName)
-- ── 1. Fetch player row from Players table ──────────────
local pRows = cargo.query("Players",
"id,real_name,image,current_team,nationality,status,game,birth_date,role," ..
"instagram,youtube,twitter,discord,facebook",
{ where = "_pageName='" .. sqlPage .. "'", limit = 1 })
local pl = (pRows and #pRows > 0) and pRows[1] or {}
local displayName = pl.id or mw.title.getCurrentTitle().subpageText
-- ── 2. Krafton rank ─────────────────────────────────────
local rankVal = "Unranked"
local rRows = cargo.query("Krafton_Rankings", "rank", {
where = string.format("(name='%s' OR name='%s') AND type='Player'",
sqlPage, esc(displayName)), limit = 1 })
if rRows and #rRows > 0 then rankVal = "#" .. rRows[1].rank end
-- ── 3. Earnings ──────────────────────────────────────────
local indEarnings, teamEarnings = 0, 0
local pWhere = string.format("(player='%s' OR player='%s')", sqlPage, esc(displayName))
local eRows = cargo.query("PrizeMoney", "SUM(prize)=total", { where = pWhere })
if eRows and #eRows > 0 then indEarnings = tonumber(eRows[1].total) or 0 end
local participation = cargo.query("Tournament_Teams", "tournament,team", {
where = string.format(
"p1='%s' OR p1='%s' OR p2='%s' OR p2='%s' OR " ..
"p3='%s' OR p3='%s' OR p4='%s' OR p4='%s' OR " ..
"p5='%s' OR p5='%s' OR p6='%s' OR p6='%s'",
sqlPage,esc(displayName), sqlPage,esc(displayName),
sqlPage,esc(displayName), sqlPage,esc(displayName),
sqlPage,esc(displayName), sqlPage,esc(displayName)),
limit = 500 })
if participation and #participation > 0 then
local conds = {}
for _, r in ipairs(participation) do
if r.tournament and r.team then
table.insert(conds, string.format(
"(tournament='%s' AND team='%s')", esc(r.tournament), esc(r.team)))
end
end
if #conds > 0 then
local tPrizes = cargo.query("PrizeMoney", "SUM(prize)=team_total", {
where = "("..table.concat(conds," OR ")..")" ..
" AND (player='' OR player IS NULL)" })
if tPrizes and #tPrizes > 0 then
teamEarnings = tonumber(tPrizes[1].team_total) or 0
end
end
end
local totalEarnings = indEarnings + teamEarnings
-- ── 4. Team history ──────────────────────────────────────
local teamHist = cargo.query("Player_Former_Teams",
"team,join_date,leave_date",
{ where = "player_id='"..sqlPage.."'", orderBy="join_date DESC", limit=15 })
if #teamHist == 0 then
teamHist = cargo.query("Player_Former_Teams",
"team,join_date,leave_date",
{ where="player_id='"..esc(displayName).."'", orderBy="join_date DESC", limit=15 })
end
-- ── 5. Tournament history ─────────────────────────────────
-- For each tournament the player appeared in, find their team's
-- final placement from StageStandings and prize from PrizeMoney
local tournHistory = {}
local seenTournStage = {}
if participation and #participation > 0 then
local tournTeamConds = {}
for _, r in ipairs(participation) do
if r.tournament and r.team then
table.insert(tournTeamConds, string.format(
"(tournament='%s' AND team='%s')", esc(r.tournament), esc(r.team)))
end
end
if #tournTeamConds > 0 then
local standings = cargo.query("StageStandings",
"tournament,stage,team,totalpts,wwcd,elimpts,result",
{ where = table.concat(tournTeamConds," OR "),
orderBy = "tournament DESC", limit = 200 })
for _, row in ipairs(standings) do
local key = row.tournament .. "|" .. row.team
-- Keep only the last stage per tournament per team (Finals > Semis > etc.)
if not seenTournStage[key] then
seenTournStage[key] = true
-- Get rank within that stage
local rankRows = cargo.query("StageStandings",
"COUNT(team)=cnt",
{ where = string.format(
"tournament='%s' AND stage='%s' AND totalpts >= %s",
esc(row.tournament), esc(row.stage),
tonumber(row.totalpts) or 0) })
local place = (rankRows and #rankRows > 0)
and (tonumber(rankRows[1].cnt) or 99) or 99
-- Prize for this tournament + team
local prizeRows = cargo.query("PrizeMoney", "SUM(prize)=total", {
where = string.format(
"tournament='%s' AND team='%s' AND (player='' OR player IS NULL)",
esc(row.tournament), esc(row.team)) })
local prize = (prizeRows and #prizeRows > 0)
and (tonumber(prizeRows[1].total) or 0) or 0
table.insert(tournHistory, {
tournament = row.tournament,
stage = row.stage,
team = row.team,
place = place,
result = row.result or "",
prize = prize
})
end
end
end
end
-- ── Build HTML ────────────────────────────────────────────
local sc, sbg, sborder = statusColor(pl.status)
local initials = displayName:sub(1,2):upper()
local root = html.create('div'):addClass('pd-dashboard')
-- ── HERO ─────────────────────────────────────────────────
local hero = root:tag('div'):addClass('pd-hero')
local photoDiv = hero:tag('div'):addClass('pd-hero-photo')
if pl.image and pl.image ~= "" then
photoDiv:wikitext('[[File:'..pl.image..'|120px|link=]]')
else
photoDiv:wikitext(initials)
end
local heroInfo = hero:tag('div'):addClass('pd-hero-info')
heroInfo:tag('div'):addClass('pd-hero-name'):wikitext(displayName)
if pl.real_name and pl.real_name ~= "" then
heroInfo:tag('div'):addClass('pd-hero-realname'):wikitext(pl.real_name)
end
local tags = heroInfo:tag('div'):addClass('pd-hero-tags')
if pl.status and pl.status ~= "" then
tags:tag('span'):addClass('pd-tag')
:css('color', sc):css('background', sbg):css('border', '1px solid '..sborder)
:wikitext('● ' .. pl.status)
end
if pl.role and pl.role ~= "" then
tags:tag('span'):addClass('pd-tag pd-tag-role'):wikitext(pl.role)
end
if pl.game and pl.game ~= "" then
tags:tag('span'):addClass('pd-tag pd-tag-game'):wikitext(pl.game)
end
if pl.nationality and pl.nationality ~= "" then
tags:tag('span'):addClass('pd-tag pd-tag-nat'):wikitext(pl.nationality)
end
if rankVal ~= "Unranked" then
heroInfo:tag('div'):addClass('pd-rank-chip')
:tag('span'):wikitext('Krafton Rank'):done()
:tag('b'):wikitext(rankVal)
end
if totalEarnings > 0 then
local heroRight = hero:tag('div'):addClass('pd-hero-right')
heroRight:tag('div'):addClass('pd-earnings-label'):wikitext('Approx. Earnings')
heroRight:tag('div'):addClass('pd-earnings-val'):wikitext(fmtCurrency(totalEarnings))
local bd = heroRight:tag('div'):addClass('pd-earnings-breakdown')
bd:tag('div'):addClass('pd-earn-sub')
:tag('div'):addClass('pd-earn-sub-label'):wikitext('Team'):done()
:tag('div'):addClass('pd-earn-sub-val'):wikitext(fmtCurrency(teamEarnings))
bd:tag('div'):addClass('pd-earn-sub')
:tag('div'):addClass('pd-earn-sub-label'):wikitext('Individual'):done()
:tag('div'):addClass('pd-earn-sub-val'):wikitext(fmtCurrency(indEarnings))
end
-- ── BODY ─────────────────────────────────────────────────
local body = root:tag('div'):addClass('pd-body')
-- Left panel
local left = body:tag('div'):addClass('pd-left')
left:tag('div'):addClass('pd-section-title'):wikitext('Player Info')
local function infoRow(label, val, link)
if not val or val == "" then return end
local row = left:tag('div'):addClass('pd-info-row')
row:tag('span'):addClass('pd-info-label'):wikitext(label)
local vspan = row:tag('span'):addClass('pd-info-val')
if link then vspan:wikitext('[['..val..']]')
else vspan:wikitext(val) end
end
infoRow('Real Name', pl.real_name)
infoRow('Born', pl.birth_date and lang:formatDate("d F Y", pl.birth_date))
infoRow('Nationality', pl.nationality)
infoRow('Role', pl.role)
infoRow('Current Team',pl.current_team, true)
infoRow('Game', pl.game)
infoRow('Krafton Rank',rankVal ~= "Unranked" and rankVal or nil)
-- Socials
local socials = {
{k='instagram', file='Icon_instagram.png', base='https://instagram.com/'},
{k='twitter', file='Icon_twitter.png', base='https://twitter.com/'},
{k='youtube', file='Icon_youtube.png', base='https://youtube.com/'},
{k='discord', file='Icon_discord.png', base='https://discord.gg/'},
{k='facebook', file='Icon_facebook.png', base='https://facebook.com/'},
}
local socialDiv = left:tag('div'):addClass('pd-socials')
for _, s in ipairs(socials) do
local v = pl[s.k]
if v and v ~= "" then
local url = v:match("^https?://") and v or (s.base .. v)
socialDiv:wikitext('[[File:'..s.file..'|24px|link='..url..'|class=social-img]]')
end
end
-- Team history
if #teamHist > 0 then
left:tag('div'):addClass('pd-section-title pd-section-title-gap'):wikitext('Team History')
for _, h in ipairs(teamHist) do
local tr = left:tag('div'):addClass('pd-team-row')
tr:tag('div'):addClass('pd-team-logo')
:wikitext((h.team or "?"):sub(1,3):upper())
tr:tag('div'):addClass('pd-team-name'):wikitext('[['..(h.teamor"")..']]')
tr:tag('div'):addClass('pd-team-dates')
:wikitext(fmtDate(h.join_date) .. ' – ' ..
(h.leave_date and h.leave_date ~= ""
and fmtDate(h.leave_date) or 'Now'))
end
end
-- Right panel — tournament history
local right = body:tag('div'):addClass('pd-right')
right:tag('div'):addClass('pd-section-title'):wikitext('Tournament History')
if #tournHistory > 0 then
local tbl = right:tag('table'):addClass('pd-tourn-table')
local hdr = tbl:tag('tr')
for _, h in ipairs({'Tournament','Team','Stage','Place','Result','Prize'}) do
hdr:tag('th'):wikitext(h)
end
for _, t in ipairs(tournHistory) do
local tr = tbl:tag('tr')
local place = t.place
local placeClass = place == 1 and 'pd-place-chip place-1'
or place == 2 and 'pd-place-chip place-2'
or place == 3 and 'pd-place-chip place-3'
or 'pd-place-chip place-other'
local res = (t.result or ""):lower()
local resBadge = res == 'q' and '<span class="pd-result-q">Qualified</span>'
or res == 'e' and '<span class="pd-result-e">Eliminated</span>'
or ""
tr:tag('td'):wikitext('[['..t.tournament..']]')
tr:tag('td'):wikitext('[['..t.team..']]')
tr:tag('td'):wikitext(t.stage or "—")
tr:tag('td'):tag('span'):addClass(placeClass):wikitext(tostring(place))
tr:tag('td'):wikitext(resBadge)
tr:tag('td'):addClass(t.prize > 0 and 'pd-prize-cell' or 'pd-prize-none')
:wikitext(t.prize > 0 and fmtCurrency(t.prize) or "—")
end
else
right:tag('div'):addClass('pd-empty')
:wikitext('No tournament data found for this player.')
end
-- Stats placeholder (ready for future)
right:tag('div'):addClass('pd-stats-placeholder')
:tag('b'):wikitext('📊 Performance Stats'):done()
:wikitext('Coming soon — per-match stats will appear here once Player_Stats data is available.')
return tostring(root)
end
return p