Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:TeamDashboard: Difference between revisions

From eSportsAmaze
No edit summary
No edit summary
Line 43: Line 43:
     return (FLAGS[c:lower():gsub("%s+",""):gsub("-","")] or "").." "
     return (FLAGS[c:lower():gsub("%s+",""):gsub("-","")] or "").." "
end
end
local roleConfig = {
local roleConfig = {
     {key="igl",    sort=1,  color="#eab308"},
     {key="igl",    sort=1,  color="#eab308"},
Line 61: Line 60:
     if not role then return "#64748b" end
     if not role then return "#64748b" end
     local r = role:lower()
     local r = role:lower()
     for _,cfg in ipairs(roleConfig) do
     for _,cfg in ipairs(roleConfig) do if r:find(cfg.key) then return cfg.color end end
        if r:find(cfg.key) then return cfg.color end
    end
     return "#64748b"
     return "#64748b"
end
end
Line 69: Line 66:
     if not role then return 99 end
     if not role then return 99 end
     local r = role:lower()
     local r = role:lower()
     for _,cfg in ipairs(roleConfig) do
     for _,cfg in ipairs(roleConfig) do if r:find(cfg.key) then return cfg.sort end end
        if r:find(cfg.key) then return cfg.sort end
    end
     return 99
     return 99
end
end
local function renderPlaceBadge(td, placement)
local function renderPlaceBadge(td, placement)
     local rank       = tonumber(placement) or 99
     local rank=tonumber(placement) or 99
     local placeText  = tostring(placement or "—")
     local txt =tostring(placement or "—")
     local badgeClass = "place-def"
     local cls ="place-def"
     if rank==1 then badgeClass="place-1"; placeText="1st"
     if rank==1 then cls="place-1"; txt="1st"
     elseif rank==2 then badgeClass="place-2"; placeText="2nd"
     elseif rank==2 then cls="place-2"; txt="2nd"
     elseif rank==3 then badgeClass="place-3"; placeText="3rd"
     elseif rank==3 then cls="place-3"; txt="3rd"
     elseif placeText:match("^%d+$") then placeText=placeText.."th"
     elseif txt:match("^%d+$") then txt=txt.."th"
     end
     end
     td:tag('span'):addClass('place-badge '..badgeClass):wikitext(placeText)
     td:tag('span'):addClass('place-badge '..cls):wikitext(txt)
end
end


Line 122: Line 116:
     if dbRows then
     if dbRows then
         for _,r in ipairs(dbRows) do
         for _,r in ipairs(dbRows) do
             dbPlayers[r.id] = {
             dbPlayers[r.id]={id=r.id, name=r.real_name or "",
                id=r.id, name=r.real_name or "", role=r.role or "Player",
                role=r.role or "Player", nat=r.nationality or "",
                nat=r.nationality or "", image=r.image or "",
                image=r.image or "", link=r._pageName or r.id}
                link=r._pageName or r.id
            }
         end
         end
     end
     end
     local roster = {}
     local roster={}
     for _,p2 in pairs(dbPlayers) do table.insert(roster,p2) end
     for _,p2 in pairs(dbPlayers) do table.insert(roster,p2) end
     for i=1,10 do
     for i=1,10 do
         local mid = clean(args["player"..i])
         local mid=clean(args["player"..i])
         if mid and not dbPlayers[mid] then
         if mid and not dbPlayers[mid] then
             table.insert(roster,{
             table.insert(roster,{id=mid, name=clean(args["name"..i]) or "",
                id=mid, name=clean(args["name"..i]) or "",
                 role=clean(args["role"..i]) or "Player",
                 role=clean(args["role"..i]) or "Player",
                 nat=clean(args["flag"..i]) or "",
                 nat=clean(args["flag"..i]) or "",
                 image=clean(args["image"..i]) or "", link=mid,
                 image=clean(args["image"..i]) or "", link=mid})
            })
         end
         end
     end
     end
Line 154: Line 144:
         orderBy="leave_date DESC", limit=200})
         orderBy="leave_date DESC", limit=200})
     fRows = fRows or {}
     fRows = fRows or {}
 
     local pageNames={}
     local pageNames = {}
     for _,r in ipairs(fRows) do
     for _,r in ipairs(fRows) do
         if r.player_id and r.player_id~="" then
         if r.player_id and r.player_id~="" then
Line 161: Line 150:
         end
         end
     end
     end
     local playerDetails = {}
     local playerDetails={}
     if #pageNames>0 then
     if #pageNames>0 then
         local dRows = cargo.query("Players","_pageName,real_name,id",
         local dRows=cargo.query("Players","_pageName,real_name,id",
             {where="_pageName IN ("..table.concat(pageNames,",")..")", limit=200})
             {where="_pageName IN ("..table.concat(pageNames,",")..")", limit=200})
         if dRows then
         if dRows then
Line 171: Line 160:
         end
         end
     end
     end
     local formerRows = {}
     local formerRows={}
     for _,r in ipairs(fRows) do
     for _,r in ipairs(fRows) do
         local d = playerDetails[r.player_id] or {}
         local d=playerDetails[r.player_id] or {}
         table.insert(formerRows,{
         table.insert(formerRows,{pid=r.player_id, role=r.role,
            pid=r.player_id, role=r.role,
             join_date=r.join_date, leave_date=r.leave_date,
             join_date=r.join_date, leave_date=r.leave_date,
             real_name=d.real_name or "", short_id=d.short_id or "",
             real_name=d.real_name or "", short_id=d.short_id or ""})
        })
     end
     end
     -- Group by year
     -- Group by year
     local formerByYear,yearOrder,yearSeen = {},{},{}
     local formerByYear,yearOrder,yearSeen={},{},{}
     for _,r in ipairs(formerRows) do
     for _,r in ipairs(formerRows) do
         local year=(r.leave_date or ""):match("^(%d%d%d%d)") or "Unknown"
         local year=(r.leave_date or ""):match("^(%d%d%d%d)") or "Unknown"
Line 193: Line 179:
     end)
     end)


     -- ── 6. Achievements filtered by team's game ─────────────────
     -- ── 6. Achievements filtered by game ─────────────────────────
    -- PrizeMoney has no game field, so we get tournament names first
     local achRaw=cargo.query("PrizeMoney","tournament,placement,prize,award",
    -- then cross-check with Tournaments.game
     local achRaw = cargo.query("PrizeMoney","tournament,placement,prize,award",
         {where="team='"..sqlTeam.."' AND (player='' OR player IS NULL)",
         {where="team='"..sqlTeam.."' AND (player='' OR player IS NULL)",
         orderBy="prize DESC", limit=100})
         orderBy="prize DESC", limit=100})
     achRaw = achRaw or {}
     achRaw=achRaw or {}
 
     local tournNames,tournSeen2={},{}
    -- Collect tournament names to fetch metadata
     local tournNames,tournSeen2 = {},{}
     for _,r in ipairs(achRaw) do
     for _,r in ipairs(achRaw) do
         if r.tournament and r.tournament~="" and not tournSeen2[r.tournament] then
         if r.tournament and r.tournament~="" and not tournSeen2[r.tournament] then
Line 209: Line 191:
         end
         end
     end
     end
 
     local tournMeta={}
    -- Fetch tier + date + game for all tournaments
     local tournMeta = {}
     if #tournNames>0 then
     if #tournNames>0 then
         local mRows = cargo.query("Tournaments","name,tier,end_date,game",
         local mRows=cargo.query("Tournaments","name,tier,end_date,game",
             {where="name IN ("..table.concat(tournNames,",")..")", limit=200})
             {where="name IN ("..table.concat(tournNames,",")..")", limit=200})
         if mRows then
         if mRows then
Line 221: Line 201:
         end
         end
     end
     end
 
     local achRows={}
    -- Filter achievements: only keep rows where tournament game matches team game
    -- If team game is blank, show all (safe fallback)
     local achRows = {}
     for _,r in ipairs(achRaw) do
     for _,r in ipairs(achRaw) do
         if teamGame=="" then
         if teamGame=="" then
             table.insert(achRows,r)
             table.insert(achRows,r)
         else
         else
             local meta = tournMeta[r.tournament or ""] or {}
             local meta=tournMeta[r.tournament or ""] or {}
             local tGame = (meta.game or ""):lower()
             local tg=(meta.game or ""):lower()
             local tTeam = teamGame:lower()
             local tq=teamGame:lower()
             -- match if game contains the team's game string (e.g. "bgmi" in "Battlegrounds Mobile India")
             if tg=="" or tg:find(tq,1,true) or tq:find(tg,1,true) then
            if tGame=="" or tGame:find(tTeam,1,true) or tTeam:find(tGame,1,true) then
                 table.insert(achRows,r)
                 table.insert(achRows,r)
             end
             end
Line 241: Line 217:
     -- ── BUILD HTML ────────────────────────────────────────────────
     -- ── BUILD HTML ────────────────────────────────────────────────


     local root = html.create('div'):addClass('td-dashboard')
     local root=html.create('div'):addClass('td-dashboard')


     -- ════ HERO ════
     -- ════ HERO ════
     local hero = root:tag('div'):addClass('td-hero')
     local hero=root:tag('div'):addClass('td-hero')
 
     local lightLogo=(tm.image and tm.image~="") and tm.image or "Shield_team.png"
     local lightLogo=(tm.image and tm.image~="") and tm.image or "Shield_team.png"
     local darkLogo =(tm.image_dark and tm.image_dark~="") and tm.image_dark or lightLogo
     local darkLogo =(tm.image_dark and tm.image_dark~="") and tm.image_dark or lightLogo
     local logoDiv = hero:tag('div'):addClass('td-hero-logo')
     local logoDiv=hero:tag('div'):addClass('td-hero-logo')
     logoDiv:wikitext("[[File:"..lightLogo.."|72px|link=|class=logo-lightmode]]")
     logoDiv:wikitext("[[File:"..lightLogo.."|72px|link=|class=logo-lightmode]]")
     logoDiv:wikitext("[[File:"..darkLogo .."|72px|link=|class=logo-darkmode]]")
     logoDiv:wikitext("[[File:"..darkLogo .."|72px|link=|class=logo-darkmode]]")


     local heroInfo = hero:tag('div'):addClass('td-hero-info')
     local heroInfo=hero:tag('div'):addClass('td-hero-info')
     heroInfo:tag('div'):addClass('td-hero-name'):wikitext(displayName)
     heroInfo:tag('div'):addClass('td-hero-name'):wikitext(displayName)
 
     local tags=heroInfo:tag('div'):addClass('pd-hero-tags')
     local tags = heroInfo:tag('div'):addClass('pd-hero-tags')
     local sl=(tm.status or "active"):lower()
     local sl=(tm.status or "active"):lower()
     local stColor,stBg,stBorder
     local sc,sbg,sborder
     if sl=="active" then
     if sl=="active" then sc="#4ade80";sbg="rgba(34,197,94,.2)";sborder="rgba(34,197,94,.35)"
        stColor="#4ade80";stBg="rgba(34,197,94,.2)";stBorder="rgba(34,197,94,.35)"
     elseif sl=="inactive" or sl=="disbanded" then sc="#f87171";sbg="rgba(239,68,68,.2)";sborder="rgba(239,68,68,.35)"
     elseif sl=="inactive" or sl=="disbanded" then
     else sc="#94a3b8";sbg="rgba(148,163,184,.2)";sborder="rgba(148,163,184,.35)" end
        stColor="#f87171";stBg="rgba(239,68,68,.2)";stBorder="rgba(239,68,68,.35)"
     else
        stColor="#94a3b8";stBg="rgba(148,163,184,.2)";stBorder="rgba(148,163,184,.35)"
    end
     tags:tag('span'):addClass('pd-tag')
     tags:tag('span'):addClass('pd-tag')
         :css('color',stColor):css('background',stBg)
         :css('color',sc):css('background',sbg):css('border','1px solid '..sborder)
        :css('border','1px solid '..stBorder)
         :wikitext('● '..(tm.status or "Active"))
         :wikitext('● '..(tm.status or "Active"))
     if teamGame~="" then
     if teamGame~="" then
Line 274: Line 243:
     if rankVal then
     if rankVal then
         tags:tag('span'):addClass('pd-tag')
         tags:tag('span'):addClass('pd-tag')
             :css('color','#fbbf24')
             :css('color','#fbbf24'):css('background','rgba(251,191,36,.15)')
            :css('background','rgba(251,191,36,.15)')
             :css('border','1px solid rgba(251,191,36,.3)')
             :css('border','1px solid rgba(251,191,36,.3)')
             :wikitext('Krafton '..rankVal)
             :wikitext('Krafton '..rankVal)
     end
     end
     if totalEarnings>0 then
     if totalEarnings>0 then
         local er = hero:tag('div'):addClass('pd-hero-right')
         local er=hero:tag('div'):addClass('pd-hero-right')
         local et = er:tag('div'):addClass('pd-earnings-total')
         local et=er:tag('div'):addClass('pd-earnings-total')
         et:tag('div'):addClass('pd-earnings-label'):wikitext('Total Earnings')
         et:tag('div'):addClass('pd-earnings-label'):wikitext('Total Earnings')
         et:tag('div'):addClass('pd-earnings-val'):wikitext(fmtCurrency(totalEarnings))
         et:tag('div'):addClass('pd-earnings-val'):wikitext(fmtCurrency(totalEarnings))
Line 288: Line 255:


     -- ════ BODY ════
     -- ════ BODY ════
     local body = root:tag('div'):addClass('td-body')
     local body=root:tag('div'):addClass('td-body')


     -- ── LEFT ─────────────────────────────────────────────────────
     -- ── LEFT ─────────────────────────────────────────────────────
     local left = body:tag('div'):addClass('td-left')
     local left=body:tag('div'):addClass('td-left')
     left:tag('div'):addClass('pd-section-title'):wikitext('Team Info')
     left:tag('div'):addClass('pd-section-title'):wikitext('Team Info')
     local function infoRow(label,val)
     local function infoRow(label,val)
         if not val or val=="" then return end
         if not val or val=="" then return end
Line 300: Line 266:
             :tag('span'):addClass('pd-info-val'):wikitext(val)
             :tag('span'):addClass('pd-info-val'):wikitext(val)
     end
     end
 
     if tm.country and tm.country~="" then infoRow('Country',getFlag(tm.country)..tm.country) end
     if tm.country and tm.country~="" then
     infoRow('Game',teamGame)
        infoRow('Country', getFlag(tm.country)..tm.country)
     if tm.short_code and tm.short_code~="" then infoRow('Tag',tm.short_code) end
    end
     if rankVal then infoRow('Krafton Rank',rankVal) end
     infoRow('Game', teamGame)
     if totalEarnings>0 then infoRow('Total Earnings',fmtCurrency(totalEarnings)) end
     if tm.short_code and tm.short_code~="" then infoRow('Tag', tm.short_code) end
     if tm.sponsors and tm.sponsors~="" then infoRow('Sponsors',tm.sponsors:gsub(",",", ")) end
     if rankVal then infoRow('Krafton Rank', rankVal) end
     if totalEarnings>0 then infoRow('Total Earnings', fmtCurrency(totalEarnings)) end
     if tm.sponsors and tm.sponsors~="" then
        infoRow('Sponsors', tm.sponsors:gsub(",",", "))
    end
 
     local playerCount=0
     local playerCount=0
     for _,pl in ipairs(roster) do
     for _,pl in ipairs(roster) do
Line 319: Line 279:
         end
         end
     end
     end
     if playerCount>0 then infoRow('Active Players', tostring(playerCount)) end
     if playerCount>0 then infoRow('Active Players',tostring(playerCount)) end
     if #formerRows>0 then infoRow('Alumni', tostring(#formerRows)) end
     if #formerRows>0 then infoRow('Alumni',tostring(#formerRows)) end


    -- Socials
     local socials={
     local socials = {
         {k='instagram',file='Icon_instagram.png',base='https://instagram.com/'},
         {k='instagram',file='Icon_instagram.png',base='https://instagram.com/'},
         {k='twitter',  file='Icon_twitter.png',  base='https://twitter.com/'  },
         {k='twitter',  file='Icon_twitter.png',  base='https://twitter.com/'  },
Line 332: Line 291:
     }
     }
     local hasSocial=false
     local hasSocial=false
     for _,s in ipairs(socials) do
     for _,s in ipairs(socials) do if tm[s.k] and tm[s.k]~="" then hasSocial=true; break end end
        if tm[s.k] and tm[s.k]~="" then hasSocial=true; break end
    end
     if hasSocial then
     if hasSocial then
         local socDiv=left:tag('div'):addClass('pd-socials')
         local socDiv=left:tag('div'):addClass('pd-socials')
Line 347: Line 304:


     -- ── RIGHT ─────────────────────────────────────────────────────
     -- ── RIGHT ─────────────────────────────────────────────────────
     local right = body:tag('div'):addClass('td-right')
     local right=body:tag('div'):addClass('td-right')


     -- ── Active Roster ─────────────────────────────────────────────
     -- ── Active Roster — reuses hero-player-card CSS ───────────────
     right:tag('div'):addClass('pd-table-title'):wikitext('👥 Active Roster')
     right:tag('div'):addClass('pd-table-title'):wikitext('👥 Active Roster')
     if #roster>0 then
     if #roster>0 then
Line 360: Line 317:
             imgDiv:wikitext("[[File:"..imgFile.."|link="..(pl.link or pl.id).."]]")
             imgDiv:wikitext("[[File:"..imgFile.."|link="..(pl.link or pl.id).."]]")
             local cb=card:tag('div'):addClass('hero-card-body')
             local cb=card:tag('div'):addClass('hero-card-body')
             cb:tag('div'):addClass('hero-role-pill')
             cb:tag('div'):addClass('hero-role-pill'):css('background-color',color)
                :css('background-color',color):wikitext(pl.role or "Player")
                :wikitext(pl.role or "Player")
             cb:tag('div'):addClass('hero-player-id')
             cb:tag('div'):addClass('hero-player-id')
                 :wikitext("[["..( pl.link or pl.id).."|"..(pl.id or "").."]]")
                 :wikitext("[["..( pl.link or pl.id).."|"..(pl.id or "").."]]")
             if pl.name~="" then
             if pl.name~="" then cb:tag('div'):addClass('hero-player-name'):wikitext(pl.name) end
                cb:tag('div'):addClass('hero-player-name'):wikitext(pl.name)
            end
             if pl.nat~="" then
             if pl.nat~="" then
                 cb:tag('div'):addClass('hero-player-flag')
                 cb:tag('div'):addClass('hero-player-flag'):wikitext(getFlag(pl.nat)..pl.nat)
                    :wikitext(getFlag(pl.nat)..pl.nat)
             end
             end
         end
         end
Line 376: Line 330:
     end
     end


     -- ── Former Players ────────────────────────────────────────────
     -- ── Former Players — year-headed sections, no JS/tabs ─────────
    -- Pure CSS tabs: hidden radio inputs + label bar + panels
     -- Tabs are impossible in MediaWiki Lua (HTML gets sanitised).
     -- All inputs, labels, and panels are direct siblings of .td-tabs-wrap children
     -- Instead: each year is a collapsible header + table. Clean and reliable.
     -- so the :checked ~ sibling selector works correctly
     if #formerRows>0 then
     if #formerRows>0 then
         right:tag('div'):addClass('pd-table-title td-section-gap')
         right:tag('div'):addClass('pd-table-title td-section-gap')
             :wikitext('📋 Former Players')
             :wikitext('📋 Former Players')


        -- Safe ID: only alphanumeric
        local tabId='tdfp'..teamName:gsub("[^%w]","")
        -- Build raw HTML string (mw.html escapes inputs/labels incorrectly)
        local tabHtml = '<div class="td-tabs-wrap">'
        -- Radio inputs first (must be siblings of label bar and panels)
        for i,year in ipairs(yearOrder) do
            local checked = (i==1) and ' checked="checked"' or ''
            tabHtml = tabHtml..'<input type="radio" class="td-radio" '
                ..'name="'..tabId..'" id="'..tabId..year..'"'..checked..'/>'
        end
        -- Label bar
        tabHtml = tabHtml..'<div class="td-tab-bar">'
         for _,year in ipairs(yearOrder) do
         for _,year in ipairs(yearOrder) do
             tabHtml = tabHtml..'<label class="td-tab-btn" for="'
             -- Year sub-header
                ..tabId..year..'">'..year..'</label>'
            right:tag('div'):addClass('td-year-header'):wikitext(year)
        end
        tabHtml = tabHtml..'</div>'
 
        -- Panels
        tabHtml = tabHtml..'<div class="td-panels">'
        for _,year in ipairs(yearOrder) do
            tabHtml = tabHtml..'<div class="td-year-panel" data-year="'..year..'">'


             -- Table header
             local tbl=right:tag('table'):addClass('pd-tourn-table td-former-table')
            tabHtml = tabHtml..'<table class="pd-tourn-table td-former-table">'
            local hdr=tbl:tag('tr')
                ..'<tr><th>Player</th><th>Name</th><th>Role</th>'
            hdr:tag('th'):wikitext('Player')
                ..'<th>Joined</th><th>Left</th></tr>'
            hdr:tag('th'):wikitext('Name')
            hdr:tag('th'):wikitext('Role')
            hdr:tag('th'):wikitext('Joined')
            hdr:tag('th'):wikitext('Left')


             for _,r in ipairs(formerByYear[year]) do
             for _,r in ipairs(formerByYear[year]) do
Line 419: Line 353:
                 local dispId=(r.short_id and r.short_id~="")
                 local dispId=(r.short_id and r.short_id~="")
                     and r.short_id or pid:gsub("^.*/","")
                     and r.short_id or pid:gsub("^.*/","")
                 local roleColor=getRoleColor(r.role)
                 local tr=tbl:tag('tr')
                 local roleBadge=""
                tr:tag('td'):css('font-weight','700')
                    :wikitext("[["..pid.."|"..dispId.."]]")
                tr:tag('td'):wikitext(r.real_name~="" and r.real_name or "—")
                 local rCell=tr:tag('td')
                 if r.role and r.role~="" then
                 if r.role and r.role~="" then
                     roleBadge='<span class="td-role-badge" style="background:'
                     rCell:tag('span'):addClass('td-role-badge')
                         ..roleColor..'">'..r.role..'</span>'
                         :css('background',getRoleColor(r.role)):wikitext(r.role)
                 else roleBadge="—" end
                 else rCell:wikitext("—") end
                 tabHtml = tabHtml..'<tr>'
                 tr:tag('td'):addClass('ac-date'):wikitext(r.join_date  or "?")
                    ..'<td style="font-weight:700">[['..'<nowiki/>'..pid..'|'..dispId..']]</td>'
                tr:tag('td'):addClass('ac-date'):wikitext(r.leave_date or "?")
                    ..'<td>'..(r.real_name~="" and r.real_name or "—")..'</td>'
                    ..'<td>'..roleBadge..'</td>'
                    ..'<td class="ac-date">'..(r.join_date  or "?")..'</td>'
                    ..'<td class="ac-date">'..(r.leave_date or "?")..'</td>'
                    ..'</tr>'
             end
             end
            tabHtml = tabHtml..'</table></div>'
        end
        tabHtml = tabHtml..'</div>'  -- td-panels
        -- Inline CSS: one rule per year for :checked → show panel + highlight label
        tabHtml = tabHtml..'<style>'
        tabHtml = tabHtml..'.td-panels .td-year-panel{display:none}'
        for _,year in ipairs(yearOrder) do
            local id=tabId..year
            -- Show panel
            tabHtml = tabHtml..'#'..id..':checked~.td-tab-bar~.td-panels'
                ..' .td-year-panel[data-year="'..year.."\"]{display:block}"
            -- Highlight label
            tabHtml = tabHtml..'#'..id..':checked~.td-tab-bar'
                ..' label[for="'..id..'"]'
                ..'{background:rgba(37,99,235,.25);color:#93c5fd;'
                ..'border-color:rgba(37,99,235,.5)}'
         end
         end
        tabHtml = tabHtml..'</style></div>'  -- close td-tabs-wrap
        right:wikitext(tabHtml)
     end
     end


     -- ── Achievements ──────────────────────────────────────────────
     -- ── Achievements — matches player dashboard style ──────────────
     right:tag('div'):addClass('pd-table-title td-section-gap')
     right:tag('div'):addClass('pd-table-title td-section-gap'):wikitext('🏆 Achievements')
        :wikitext('🏆 Achievements')
     if #achRows>0 then
     if #achRows>0 then
         local tbl2=right:tag('table'):addClass('pd-tourn-table')
         local tbl2=right:tag('table'):addClass('pd-tourn-table')
Line 465: Line 376:
         hdr2:tag('th'):wikitext('Tier')
         hdr2:tag('th'):wikitext('Tier')
         hdr2:tag('th'):wikitext('Tournament')
         hdr2:tag('th'):wikitext('Tournament')
         hdr2:tag('th'):addClass('ac-place'):wikitext('Place')
         hdr2:tag('th'):addClass('td-place-col'):wikitext('Place / Award')
         hdr2:tag('th'):css('text-align','right'):wikitext('Prize')
         hdr2:tag('th'):css('text-align','right'):wikitext('Prize')


Line 480: Line 391:
             tr2:tag('td'):css('font-weight','600')
             tr2:tag('td'):css('font-weight','600')
                 :wikitext("[["..(r.tournament or "").."]]")
                 :wikitext("[["..(r.tournament or "").."]]")
             local pTd=tr2:tag('td'):addClass('ac-place')
             local pTd=tr2:tag('td'):addClass('ac-place td-place-col')
             if r.award and r.award~="" then
             if r.award and r.award~="" then
                 pTd:tag('span'):addClass('pd-award-badge'):wikitext(r.award)
                 pTd:tag('span'):addClass('pd-award-badge'):wikitext(r.award)
             else renderPlaceBadge(pTd,r.placement) end
             else
                renderPlaceBadge(pTd,r.placement)
            end
             tr2:tag('td'):addClass('ac-prize')
             tr2:tag('td'):addClass('ac-prize')
                 :wikitext(tonumber(r.prize) and tonumber(r.prize)>0
                 :wikitext(tonumber(r.prize) and tonumber(r.prize)>0

Revision as of 03:42, 9 March 2026

Documentation for this module may be created at Module:TeamDashboard/doc

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 clean(s)
    if not s then return nil end
    local c = s:gsub("[\r\n]",""):gsub("^%s*(.-)%s*$","%1")
    return c ~= "" and c or nil
end
local function fmtCurrency(n)
    if not n or n == 0 then return "—" end
    local num = math.floor(tonumber(n) or 0)
    local s   = tostring(num)
    if #s <= 3 then return "₹ " .. s end
    local result = s:sub(-3)
    local rem    = s:sub(1,-4)
    while #rem > 2 do result = rem:sub(-2)..","..result; rem = rem:sub(1,-3) end
    return "₹ " .. rem .. "," .. result
end
local function getTierClass(tier)
    if not tier then return "tier-def" end
    local t = tier:lower()
    if t:find("s") and t:find("tier") then return "tier-s" end
    if t:find("a") and t:find("tier") then return "tier-a" end
    if t:find("b") and t:find("tier") then return "tier-b" end
    if t:find("c") and t:find("tier") then return "tier-c" end
    return "tier-def"
end
local FLAGS = {
    india="🇮🇳",bangladesh="🇧🇩",pakistan="🇵🇰",nepal="🇳🇵",
    srilanka="🇱🇰",myanmar="🇲🇲",indonesia="🇮🇩",thailand="🇹🇭",
    malaysia="🇲🇾",philippines="🇵🇭",vietnam="🇻🇳",singapore="🇸🇬",
    china="🇨🇳",japan="🇯🇵",korea="🇰🇷",usa="🇺🇸",
    uk="🇬🇧",germany="🇩🇪",brazil="🇧🇷",australia="🇦🇺"
}
local function getFlag(c)
    if not c or c=="" then return "" end
    return (FLAGS[c:lower():gsub("%s+",""):gsub("-","")] or "").." "
end
local roleConfig = {
    {key="igl",     sort=1,  color="#eab308"},
    {key="filter",  sort=2,  color="#14b8a6"},
    {key="entry",   sort=3,  color="#f97316"},
    {key="assault", sort=4,  color="#3b82f6"},
    {key="fragger", sort=4,  color="#3b82f6"},
    {key="support", sort=5,  color="#22c55e"},
    {key="medic",   sort=5,  color="#22c55e"},
    {key="scout",   sort=6,  color="#14b8a6"},
    {key="sniper",  sort=7,  color="#ef4444"},
    {key="coach",   sort=8,  color="#a855f7"},
    {key="analyst", sort=9,  color="#a855f7"},
    {key="manager", sort=10, color="#1f2937"},
}
local function getRoleColor(role)
    if not role then return "#64748b" end
    local r = role:lower()
    for _,cfg in ipairs(roleConfig) do if r:find(cfg.key) then return cfg.color end end
    return "#64748b"
end
local function getRoleSort(role)
    if not role then return 99 end
    local r = role:lower()
    for _,cfg in ipairs(roleConfig) do if r:find(cfg.key) then return cfg.sort end end
    return 99
end
local function renderPlaceBadge(td, placement)
    local rank=tonumber(placement) or 99
    local txt =tostring(placement or "—")
    local cls ="place-def"
    if rank==1 then cls="place-1"; txt="1st"
    elseif rank==2 then cls="place-2"; txt="2nd"
    elseif rank==3 then cls="place-3"; txt="3rd"
    elseif txt:match("^%d+$") then txt=txt.."th"
    end
    td:tag('span'):addClass('place-badge '..cls):wikitext(txt)
end

-- ── Main ─────────────────────────────────────────────────────────

function p.main(frame)
    local args     = (frame:getParent() and frame:getParent().args) or frame.args
    local teamName = clean(args.team) or mw.title.getCurrentTitle().subpageText
    local sqlTeam  = esc(teamName)

    -- ── 1. Team data ──────────────────────────────────────────────
    local tRows = cargo.query("Teams",
        "display_name,short_code,game,image,image_dark,country,status,"
        .."sponsors,instagram,twitter,youtube,facebook,discord,website",
        {where="name='"..sqlTeam.."'", limit=1})
    local tm = (tRows and #tRows>0) and tRows[1] or {}
    local displayName = (tm.display_name and tm.display_name~="")
        and tm.display_name or teamName
    local teamGame = tm.game or ""

    -- ── 2. Krafton rank ───────────────────────────────────────────
    local rankVal = nil
    local rRows = cargo.query("Krafton_Rankings","rank",
        {where="name='"..sqlTeam.."' AND type='Team'", limit=1})
    if rRows and #rRows>0 then rankVal="#"..rRows[1].rank end

    -- ── 3. Total earnings ─────────────────────────────────────────
    local totalEarnings = 0
    local eRows = cargo.query("PrizeMoney","SUM(prize)=total",
        {where="team='"..sqlTeam.."' AND (player='' OR player IS NULL)"})
    if eRows and #eRows>0 then totalEarnings=tonumber(eRows[1].total) or 0 end

    -- ── 4. Active roster ─────────────────────────────────────────
    local dbPlayers = {}
    local dbRows = cargo.query("Players","id,real_name,role,nationality,image,_pageName",
        {where="current_team='"..sqlTeam.."' AND status='Active'", limit=20})
    if dbRows then
        for _,r in ipairs(dbRows) do
            dbPlayers[r.id]={id=r.id, name=r.real_name or "",
                role=r.role or "Player", nat=r.nationality or "",
                image=r.image or "", link=r._pageName or r.id}
        end
    end
    local roster={}
    for _,p2 in pairs(dbPlayers) do table.insert(roster,p2) end
    for i=1,10 do
        local mid=clean(args["player"..i])
        if mid and not dbPlayers[mid] then
            table.insert(roster,{id=mid, name=clean(args["name"..i]) or "",
                role=clean(args["role"..i]) or "Player",
                nat=clean(args["flag"..i]) or "",
                image=clean(args["image"..i]) or "", link=mid})
        end
    end
    table.sort(roster,function(a,b)
        local sa,sb=getRoleSort(a.role),getRoleSort(b.role)
        if sa~=sb then return sa<sb end
        return (a.id or ""):lower()<(b.id or ""):lower()
    end)

    -- ── 5. Former players ─────────────────────────────────────────
    local fRows = cargo.query("Player_Former_Teams",
        "player_id,role,join_date,leave_date",
        {where="team='"..sqlTeam.."' AND leave_date!=''",
         orderBy="leave_date DESC", limit=200})
    fRows = fRows or {}
    local pageNames={}
    for _,r in ipairs(fRows) do
        if r.player_id and r.player_id~="" then
            table.insert(pageNames,"'"..esc(r.player_id).."'")
        end
    end
    local playerDetails={}
    if #pageNames>0 then
        local dRows=cargo.query("Players","_pageName,real_name,id",
            {where="_pageName IN ("..table.concat(pageNames,",")..")", limit=200})
        if dRows then
            for _,d in ipairs(dRows) do
                playerDetails[d._pageName]={real_name=d.real_name, short_id=d.id}
            end
        end
    end
    local formerRows={}
    for _,r in ipairs(fRows) do
        local d=playerDetails[r.player_id] or {}
        table.insert(formerRows,{pid=r.player_id, role=r.role,
            join_date=r.join_date, leave_date=r.leave_date,
            real_name=d.real_name or "", short_id=d.short_id or ""})
    end
    -- Group by year
    local formerByYear,yearOrder,yearSeen={},{},{}
    for _,r in ipairs(formerRows) do
        local year=(r.leave_date or ""):match("^(%d%d%d%d)") or "Unknown"
        if not yearSeen[year] then yearSeen[year]=true; table.insert(yearOrder,year) end
        if not formerByYear[year] then formerByYear[year]={} end
        table.insert(formerByYear[year],r)
    end
    table.sort(yearOrder,function(a,b)
        return (tonumber(a) or 0)>(tonumber(b) or 0)
    end)

    -- ── 6. Achievements filtered by game ─────────────────────────
    local achRaw=cargo.query("PrizeMoney","tournament,placement,prize,award",
        {where="team='"..sqlTeam.."' AND (player='' OR player IS NULL)",
         orderBy="prize DESC", limit=100})
    achRaw=achRaw or {}
    local tournNames,tournSeen2={},{}
    for _,r in ipairs(achRaw) do
        if r.tournament and r.tournament~="" and not tournSeen2[r.tournament] then
            tournSeen2[r.tournament]=true
            table.insert(tournNames,"'"..esc(r.tournament).."'")
        end
    end
    local tournMeta={}
    if #tournNames>0 then
        local mRows=cargo.query("Tournaments","name,tier,end_date,game",
            {where="name IN ("..table.concat(tournNames,",")..")", limit=200})
        if mRows then
            for _,row in ipairs(mRows) do
                tournMeta[row.name]={tier=row.tier, date=row.end_date, game=row.game}
            end
        end
    end
    local achRows={}
    for _,r in ipairs(achRaw) do
        if teamGame=="" then
            table.insert(achRows,r)
        else
            local meta=tournMeta[r.tournament or ""] or {}
            local tg=(meta.game or ""):lower()
            local tq=teamGame:lower()
            if tg=="" or tg:find(tq,1,true) or tq:find(tg,1,true) then
                table.insert(achRows,r)
            end
        end
    end

    -- ── BUILD HTML ────────────────────────────────────────────────

    local root=html.create('div'):addClass('td-dashboard')

    -- ════ HERO ════
    local hero=root:tag('div'):addClass('td-hero')
    local lightLogo=(tm.image and tm.image~="") and tm.image or "Shield_team.png"
    local darkLogo =(tm.image_dark and tm.image_dark~="") and tm.image_dark or lightLogo
    local logoDiv=hero:tag('div'):addClass('td-hero-logo')
    logoDiv:wikitext("[[File:"..lightLogo.."|72px|link=|class=logo-lightmode]]")
    logoDiv:wikitext("[[File:"..darkLogo .."|72px|link=|class=logo-darkmode]]")

    local heroInfo=hero:tag('div'):addClass('td-hero-info')
    heroInfo:tag('div'):addClass('td-hero-name'):wikitext(displayName)
    local tags=heroInfo:tag('div'):addClass('pd-hero-tags')
    local sl=(tm.status or "active"):lower()
    local sc,sbg,sborder
    if sl=="active" then sc="#4ade80";sbg="rgba(34,197,94,.2)";sborder="rgba(34,197,94,.35)"
    elseif sl=="inactive" or sl=="disbanded" then sc="#f87171";sbg="rgba(239,68,68,.2)";sborder="rgba(239,68,68,.35)"
    else sc="#94a3b8";sbg="rgba(148,163,184,.2)";sborder="rgba(148,163,184,.35)" end
    tags:tag('span'):addClass('pd-tag')
        :css('color',sc):css('background',sbg):css('border','1px solid '..sborder)
        :wikitext('● '..(tm.status or "Active"))
    if teamGame~="" then
        tags:tag('span'):addClass('pd-tag pd-tag-game'):wikitext(teamGame)
    end
    if rankVal then
        tags:tag('span'):addClass('pd-tag')
            :css('color','#fbbf24'):css('background','rgba(251,191,36,.15)')
            :css('border','1px solid rgba(251,191,36,.3)')
            :wikitext('Krafton '..rankVal)
    end
    if totalEarnings>0 then
        local er=hero:tag('div'):addClass('pd-hero-right')
        local et=er:tag('div'):addClass('pd-earnings-total')
        et:tag('div'):addClass('pd-earnings-label'):wikitext('Total Earnings')
        et:tag('div'):addClass('pd-earnings-val'):wikitext(fmtCurrency(totalEarnings))
    end

    -- ════ BODY ════
    local body=root:tag('div'):addClass('td-body')

    -- ── LEFT ─────────────────────────────────────────────────────
    local left=body:tag('div'):addClass('td-left')
    left:tag('div'):addClass('pd-section-title'):wikitext('Team Info')
    local function infoRow(label,val)
        if not val or val=="" then return end
        left:tag('div'):addClass('pd-info-row')
            :tag('span'):addClass('pd-info-label'):wikitext(label):done()
            :tag('span'):addClass('pd-info-val'):wikitext(val)
    end
    if tm.country and tm.country~="" then infoRow('Country',getFlag(tm.country)..tm.country) end
    infoRow('Game',teamGame)
    if tm.short_code and tm.short_code~="" then infoRow('Tag',tm.short_code) end
    if rankVal then infoRow('Krafton Rank',rankVal) end
    if totalEarnings>0 then infoRow('Total Earnings',fmtCurrency(totalEarnings)) end
    if tm.sponsors and tm.sponsors~="" then infoRow('Sponsors',tm.sponsors:gsub(",",", ")) end
    local playerCount=0
    for _,pl in ipairs(roster) do
        local r=(pl.role or ""):lower()
        if not r:find("coach") and not r:find("analyst") and not r:find("manager") then
            playerCount=playerCount+1
        end
    end
    if playerCount>0 then infoRow('Active Players',tostring(playerCount)) end
    if #formerRows>0 then infoRow('Alumni',tostring(#formerRows)) end

    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/' },
        {k='website',  file='Icon_website.png',  base='https://'              },
    }
    local hasSocial=false
    for _,s in ipairs(socials) do if tm[s.k] and tm[s.k]~="" then hasSocial=true; break end end
    if hasSocial then
        local socDiv=left:tag('div'):addClass('pd-socials')
        for _,s in ipairs(socials) do
            local v=tm[s.k]
            if v and v~="" then
                local url=v:match("^https?://") and v or (s.base..v)
                socDiv:wikitext("[[File:"..s.file.."|32px|link="..url.."|class=social-img]]")
            end
        end
    end

    -- ── RIGHT ─────────────────────────────────────────────────────
    local right=body:tag('div'):addClass('td-right')

    -- ── Active Roster — reuses hero-player-card CSS ───────────────
    right:tag('div'):addClass('pd-table-title'):wikitext('👥 Active Roster')
    if #roster>0 then
        local grid=right:tag('div'):addClass('hero-roster-grid')
        for _,pl in ipairs(roster) do
            local card=grid:tag('div'):addClass('hero-player-card')
            local color=getRoleColor(pl.role)
            local imgDiv=card:tag('div'):addClass('hero-card-image')
            local imgFile=(pl.image~="") and pl.image or "Player_Placeholder.png"
            imgDiv:wikitext("[[File:"..imgFile.."|link="..(pl.link or pl.id).."]]")
            local cb=card:tag('div'):addClass('hero-card-body')
            cb:tag('div'):addClass('hero-role-pill'):css('background-color',color)
                :wikitext(pl.role or "Player")
            cb:tag('div'):addClass('hero-player-id')
                :wikitext("[["..( pl.link or pl.id).."|"..(pl.id or "").."]]")
            if pl.name~="" then cb:tag('div'):addClass('hero-player-name'):wikitext(pl.name) end
            if pl.nat~="" then
                cb:tag('div'):addClass('hero-player-flag'):wikitext(getFlag(pl.nat)..pl.nat)
            end
        end
    else
        right:tag('div'):addClass('pd-empty'):wikitext('No active roster data found.')
    end

    -- ── Former Players — year-headed sections, no JS/tabs ─────────
    -- Tabs are impossible in MediaWiki Lua (HTML gets sanitised).
    -- Instead: each year is a collapsible header + table. Clean and reliable.
    if #formerRows>0 then
        right:tag('div'):addClass('pd-table-title td-section-gap')
            :wikitext('📋 Former Players')

        for _,year in ipairs(yearOrder) do
            -- Year sub-header
            right:tag('div'):addClass('td-year-header'):wikitext(year)

            local tbl=right:tag('table'):addClass('pd-tourn-table td-former-table')
            local hdr=tbl:tag('tr')
            hdr:tag('th'):wikitext('Player')
            hdr:tag('th'):wikitext('Name')
            hdr:tag('th'):wikitext('Role')
            hdr:tag('th'):wikitext('Joined')
            hdr:tag('th'):wikitext('Left')

            for _,r in ipairs(formerByYear[year]) do
                local pid=r.pid or ""
                local dispId=(r.short_id and r.short_id~="")
                    and r.short_id or pid:gsub("^.*/","")
                local tr=tbl:tag('tr')
                tr:tag('td'):css('font-weight','700')
                    :wikitext("[["..pid.."|"..dispId.."]]")
                tr:tag('td'):wikitext(r.real_name~="" and r.real_name or "—")
                local rCell=tr:tag('td')
                if r.role and r.role~="" then
                    rCell:tag('span'):addClass('td-role-badge')
                        :css('background',getRoleColor(r.role)):wikitext(r.role)
                else rCell:wikitext("—") end
                tr:tag('td'):addClass('ac-date'):wikitext(r.join_date  or "?")
                tr:tag('td'):addClass('ac-date'):wikitext(r.leave_date or "?")
            end
        end
    end

    -- ── Achievements — matches player dashboard style ──────────────
    right:tag('div'):addClass('pd-table-title td-section-gap'):wikitext('🏆 Achievements')
    if #achRows>0 then
        local tbl2=right:tag('table'):addClass('pd-tourn-table')
        local hdr2=tbl2:tag('tr')
        hdr2:tag('th'):wikitext('Date')
        hdr2:tag('th'):wikitext('Tier')
        hdr2:tag('th'):wikitext('Tournament')
        hdr2:tag('th'):addClass('td-place-col'):wikitext('Place / Award')
        hdr2:tag('th'):css('text-align','right'):wikitext('Prize')

        for _,r in ipairs(achRows) do
            local meta=tournMeta[r.tournament or ""] or {}
            local tr2=tbl2:tag('tr')
            tr2:tag('td'):addClass('ac-date')
                :wikitext(meta.date and meta.date~="" and meta.date or "—")
            local tierTd=tr2:tag('td'):addClass('ac-tier')
            if meta.tier and meta.tier~="" then
                tierTd:tag('span'):addClass('tier-badge '..getTierClass(meta.tier))
                    :wikitext(meta.tier)
            else tierTd:wikitext("—") end
            tr2:tag('td'):css('font-weight','600')
                :wikitext("[["..(r.tournament or "").."]]")
            local pTd=tr2:tag('td'):addClass('ac-place td-place-col')
            if r.award and r.award~="" then
                pTd:tag('span'):addClass('pd-award-badge'):wikitext(r.award)
            else
                renderPlaceBadge(pTd,r.placement)
            end
            tr2:tag('td'):addClass('ac-prize')
                :wikitext(tonumber(r.prize) and tonumber(r.prize)>0
                    and fmtCurrency(tonumber(r.prize)) or "—")
        end
    else
        right:tag('div'):addClass('pd-empty'):wikitext('No achievements recorded.')
    end

    return tostring(root)
end

return p