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

Module:Team: Difference between revisions

From eSportsAmaze
No edit summary
Tag: Reverted
No edit summary
 
(27 intermediate revisions by 2 users not shown)
Line 5: Line 5:


-- ============================================================
-- ============================================================
-- HELPER FUNCTIONS
-- HELPER: Argument Fetcher
-- ============================================================
-- ============================================================
local function getArgs(frame)
    local args = {}
    if frame:getParent() then
        for k, v in pairs(frame:getParent().args) do args[k] = v end
    end
    for k, v in pairs(frame.args) do args[k] = v end
    return args
end
-- ============================================================
-- HELPER: Sanitize Strings
-- ============================================================
local function clean(s)
    if not s then return nil end
    local cleaned = s:gsub("[\r\n]", ""):gsub("^%s*(.-)%s*$", "%1")
    if cleaned == "" then return nil end
    return cleaned
end
-- ============================================================
-- HELPER: Tier Class (MATCHES TOURNAMENT MODULE EXACTLY)
-- ============================================================
local function getTierClass(tier)
    if not tier then return "tier-def" end
    local t = tier:lower()
    -- Loose matching to catch "A Tier", "A-Tier", "Tier A"
    if string.find(t, "s") and string.find(t, "tier") then return "tier-s" end
    if string.find(t, "a") and string.find(t, "tier") then return "tier-a" end
    if string.find(t, "b") and string.find(t, "tier") then return "tier-b" end
    if string.find(t, "c") and string.find(t, "tier") then return "tier-c" end
    return "tier-def"
end


local function formatCurrency(amount)
local function formatCurrency(amount)
Line 19: Line 51:
     local hasSocials = false
     local hasSocials = false
     local platforms = {
     local platforms = {
         {arg='instagram', file='Icon_instagram.png'},
         {arg='instagram', file='Icon_instagram.png', base='https://www.instagram.com/'},
         {arg='twitter',  file='Icon_twitter.png'},
         {arg='twitter',  file='Icon_twitter.png',  base='https://twitter.com/'},
         {arg='youtube',  file='Icon_youtube.png'},
         {arg='youtube',  file='Icon_youtube.png',  base='https://www.youtube.com/'},
         {arg='discord',  file='Icon_discord.png'},
         {arg='discord',  file='Icon_discord.png',  base='https://discord.gg/'},
         {arg='facebook',  file='Icon_facebook.png'},
         {arg='facebook',  file='Icon_facebook.png',  base='https://www.facebook.com/'},
         {arg='website',  file='Icon_website.png'}
         {arg='website',  file='Icon_website.png'}
     }
     }
     for _, p in ipairs(platforms) do
     for _, p in ipairs(platforms) do
         if args[p.arg] and args[p.arg] ~= "" then
         local val = args[p.arg]
        if val and val ~= "" then
             hasSocials = true
             hasSocials = true
             container:wikitext('[[File:' .. p.file .. '|24px|link=' .. args[p.arg] .. '|class=social-img]]')
            local link
            if p.arg == 'website' then
                link = val
            elseif val:match("^https?://") then
                link = val
            else
                link = p.base .. val
            end
             container:wikitext('[[File:' .. p.file .. '|24px|link=' .. link .. '|class=social-img]]')
         end
         end
     end
     end
     if hasSocials then return tostring(container) else return "" end
 
     if hasSocials then
        return tostring(container)
    end
    return ""
end
end


Line 52: Line 97:
-- ============================================================
-- ============================================================
function p.infobox(frame)
function p.infobox(frame)
     local args = frame:getParent().args
     local args = getArgs(frame)
     local team = args.name or currentTitle.subpageText
     local team = clean(args.name) or currentTitle.subpageText
      
      
     local root = html.create('div'):addClass('flat-infobox')
     local root = html.create('div'):addClass('flat-infobox')
     root:tag('div'):addClass('fib-header'):tag('div'):addClass('fib-title'):wikitext(team)
     root:tag('div'):addClass('fib-header'):tag('div'):addClass('fib-title'):wikitext(team)
     root:wikitext(getInfoboxLogo(team, args.image, args.image_dark))
     root:wikitext(getInfoboxLogo(team, clean(args.image), clean(args.image_dark)))
      
      
    -- Earnings Calc
     local earnings = "0"
     local earnings = "0"
     if cargo and cargo.query then
     if cargo and cargo.query then
Line 72: Line 116:
     end
     end
      
      
    -- Status
     local statusColor = "#333"
     local statusColor = "#333"
     local statusText = args.status or "Active"
     local statusText = clean(args.status) or "Active"
     if args.status then
     if args.status then
         local s = args.status:lower()
         local s = args.status:lower()
Line 85: Line 128:


     local grid2 = root:tag('div'):addClass('fib-grid')
     local grid2 = root:tag('div'):addClass('fib-grid')
     grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Country'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.country or 'TBD'):done()
     grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Country'):done():tag('div'):addClass('fib-value-sm'):wikitext(clean(args.country) or 'TBD'):done()
     grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Tag'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.short_code or '-'):done()
     grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Tag'):done():tag('div'):addClass('fib-value-sm'):wikitext(clean(args.short_code) or '-'):done()


     if earnings and tonumber(earnings) and tonumber(earnings) > 0 then
     if earnings and tonumber(earnings) and tonumber(earnings) > 0 then
Line 97: Line 140:
     end
     end
      
      
     addRow('Full Name', args.other_team)
     addRow('Display Name', clean(args.other_team))
     if args.sponsors then addRow('Sponsors', args.sponsors:gsub(",", "<br>")) end
     if args.sponsors then addRow('Sponsors', args.sponsors:gsub(",", "<br>")) end
     root:wikitext(getSocials(args))
     root:wikitext(getSocials(args))
Line 104: Line 147:


-- ============================================================
-- ============================================================
-- MAIN 2: HYBRID ACTIVE ROSTER (HERO GRID)
-- MAIN 2: HYBRID ROSTER (SORTED BY ROLE)
-- ============================================================
-- ============================================================
function p.roster(frame)
function p.roster(frame)
     local args = frame:getParent().args
     local args = getArgs(frame)
     local team = args.team or currentTitle.subpageText
     local team = clean(args.team) or currentTitle.subpageText
      
      
     -- 1. Fetch Database Players
     -- 1. Fetch Database Players
Line 116: Line 159:
         local fields = "id, real_name, role, nationality, image, _pageName"
         local fields = "id, real_name, role, nationality, image, _pageName"
         local where = "current_team = '" .. team:gsub("'", "\\'") .. "' AND status='Active'"
         local where = "current_team = '" .. team:gsub("'", "\\'") .. "' AND status='Active'"
         local results = cargo.query(tables, fields, { where = where, orderBy = "role ASC" })
         local results = cargo.query(tables, fields, { where = where })
          
          
         for _, row in ipairs(results) do
         for _, row in ipairs(results) do
Line 123: Line 166:
                 name = row.real_name,
                 name = row.real_name,
                 role = row.role,
                 role = row.role,
                 flag = row.nationality,
                 flag = clean(row.nationality),
                 image = row.image,
                 image = clean(row.image),
                 link = row._pageName,
                 link = row._pageName,
                 source = "auto"
                 source = "auto"
Line 131: Line 174:
     end
     end
      
      
     -- 2. Process Manual Inputs (Check for duplicates)
     -- 2. Process Manual Inputs
     local finalRoster = {}
     local finalRoster = {}
   
     for _, pData in pairs(dbPlayers) do table.insert(finalRoster, pData) end
    -- Add DB players first
     for _, pData in pairs(dbPlayers) do
        table.insert(finalRoster, pData)
    end
   
    -- Check manual args (player1, player2...)
     for i = 1, 10 do
     for i = 1, 10 do
         local mid = args['player' .. i]
         local mid = clean(args['player' .. i])
         if mid and mid ~= "" then
         if mid and mid ~= "" then
            -- Only add if NOT in DB list
             if not dbPlayers[mid] then
             if not dbPlayers[mid] then
                 table.insert(finalRoster, {
                 table.insert(finalRoster, {
                     id = mid,
                     id = mid,
                     name = args['name' .. i] or "",
                     name = clean(args['name' .. i]) or "",
                     role = args['role' .. i] or "Player",
                     role = clean(args['role' .. i]) or "Player",
                     flag = args['flag' .. i] or "India",
                     flag = clean(args['flag' .. i]) or "India",
                     image = "", -- Manual entries usually have no image
                     image = clean(args['image' .. i]) or "",  
                     link = mid, -- Redlink assumption
                     link = mid,  
                     source = "manual"
                     source = "manual"
                 })
                 })
Line 158: Line 194:
     end
     end
      
      
     -- 3. Render the Grid
     -- 3. Define Role Hierarchy & Colors
     local grid = html.create('div'):addClass('roster-grid')
local roleConfig = {
        { key = "igl",      sort = 1, color = "#eab308" }, -- Gold
        { key = "filter",  sort = 2, color = "#14b8a6" }, -- Teal (New Position)
        { key = "entry",    sort = 3, color = "#f97316" }, -- Orange
        { key = "assault",  sort = 4, color = "#3b82f6" }, -- Blue
        { key = "fragger",  sort = 4, color = "#3b82f6" }, -- Blue
        { key = "support",  sort = 5, color = "#22c55e" }, -- Green
        { key = "medic",    sort = 5, color = "#22c55e" }, -- Green
        { key = "scout",    sort = 6, color = "#14b8a6" }, -- Teal
        { key = "sniper",  sort = 7, color = "#ef4444" }, -- Red
        { key = "coach",    sort = 8, color = "#a855f7" }, -- Purple
        { key = "analyst",  sort = 9, color = "#a855f7" }, -- Purple
        { key = "manager",  sort = 10, color = "#1f2937" } -- Dark Grey
    }
   
    -- 4. Assign Sort Priority & Color
    for _, player in ipairs(finalRoster) do
        local r = (player.role or ""):lower()
        player.sortOrder = 99
        player.color = "#64748b" -- Gray
       
        for _, config in ipairs(roleConfig) do
            if r:find(config.key) then
                player.sortOrder = config.sort
                player.color = config.color
                break
            end
        end
    end
   
    -- 5. Sort
    table.sort(finalRoster, function(a, b)
        if a.sortOrder ~= b.sortOrder then
            return a.sortOrder < b.sortOrder
        else
            return (a.id or ""):lower() < (b.id or ""):lower()
        end
    end)
   
    -- 6. Render
     local grid = html.create('div'):addClass('hero-roster-grid')
      
      
     for _, player in ipairs(finalRoster) do
     for _, player in ipairs(finalRoster) do
         local card = grid:tag('div'):addClass('roster-card')
         local card = grid:tag('div'):addClass('hero-player-card')
          
          
         -- Header (Image Area)
         -- Header
         local header = card:tag('div'):addClass('player-card-header')
         local header = card:tag('div'):addClass('hero-card-image')
         if player.image and player.image ~= "" then
         if player.image and player.image ~= "" then
             header:wikitext('[[File:' .. player.image .. '|link=' .. player.link .. ']]')
             header:wikitext('[[File:' .. player.image .. '|link=' .. player.link .. ']]')
         else
         else
            -- Fallback Silhouette
             header:wikitext('[[File:Player_Placeholder.png|link=' .. player.link .. ']]')
             header:wikitext('[[File:Player_Placeholder.png|link=' .. player.link .. ']]')
         end
         end
          
          
         -- Info Body
         -- Body
         local body = card:tag('div'):addClass('flat-card-body')
         local body = card:tag('div'):addClass('hero-card-body')
       
        -- Role Pill
        local roleColor = "#64748b" -- Default Gray
        local r = (player.role or ""):lower()
        if r:find("igl") then roleColor = "#eab308" -- Gold
        elseif r:find("fragger") or r:find("entry") then roleColor = "#ef4444" -- Red
        elseif r:find("support") or r:find("medic") then roleColor = "#22c55e" -- Green
        elseif r:find("sniper") then roleColor = "#3b82f6" -- Blue
        end
          
          
         body:tag('div'):addClass('roster-role-pill')
         body:tag('div'):addClass('hero-role-pill')
             :css('background-color', roleColor)
             :css('background-color', player.color)
             :wikitext(player.role or "Player")
             :wikitext(player.role or "Player")
              
              
        -- ID and Name
         body:tag('div'):addClass('hero-player-id'):wikitext('[[' .. player.link .. '|' .. player.id .. ']]')
         body:tag('div'):addClass('roster-id'):wikitext('[[' .. player.link .. '|' .. player.id .. ']]')
         if player.name and player.name ~= "" then
         if player.name and player.name ~= "" then
             body:tag('div'):addClass('roster-name'):wikitext(player.name)
             body:tag('div'):addClass('hero-player-name'):wikitext(player.name)
         end
         end
          
          
        -- Flag
         if player.flag then
         if player.flag then
             body:tag('div'):addClass('roster-flag'):wikitext('[[File:Flag_' .. player.flag .. '.png|20px]] ' .. player.flag)
            local safeFlag = player.flag:gsub(" ", "_")
            local flagFile = "Flag_" .. safeFlag .. ".png"
             body:tag('div'):addClass('hero-player-flag'):wikitext('[[File:' .. flagFile .. '|link=]] ' .. player.flag)
         end
         end
     end
     end
Line 205: Line 271:


-- ============================================================
-- ============================================================
-- MAIN 3: FORMER PLAYERS LIST
-- MAIN 3: FORMER PLAYERS LIST (NO JOIN + FLAT UI DESIGN)
-- ============================================================
-- ============================================================
function p.formerPlayers(frame)
function p.formerPlayers(frame)
     local args = frame:getParent().args
     local args = getArgs(frame)
     local team = args.team or currentTitle.subpageText
     local team = clean(args.team) or currentTitle.subpageText
      
      
     -- Query Player_Former_Teams + Join Players to get Real Name
     -- STEP 1: Get History
     local results = cargo.query("Player_Former_Teams, Players",  
     local history = cargo.query(
         "Player_Former_Teams.player_id=id, Players.real_name=Name, Player_Former_Teams.role=role, Player_Former_Teams.join_date=join_date, Player_Former_Teams.leave_date=leave_date",  
        "Player_Former_Teams",  
         "player_id, role, join_date, leave_date",  
         {
         {
            joinOn = "Player_Former_Teams.player_id = Players.id", -- Try joining on ID
             where = "team = '" .. team:gsub("'", "\\'") .. "' AND leave_date != ''",
             where = "Player_Former_Teams.team = '" .. team:gsub("'", "\\'") .. "'",
             orderBy = "leave_date DESC",
             orderBy = "Player_Former_Teams.leave_date DESC"
            limit = 100
         }
         }
     )
     )
      
      
     if not results or #results == 0 then
     if not history or #history == 0 then
         return '<div style="font-style:italic; color:#64748b; padding:10px;">No former players recorded.</div>'
         return '<div style="font-style:italic; color:#64748b; padding:10px;">No former players recorded.</div>'
     end
     end
      
      
     local tbl = html.create('table'):addClass('wikitable flat-table sortable'):css('width','100%')
    -- STEP 2: Get Page Names
    local pageNames = {}
    for i, row in ipairs(history) do
        local pName = row.player_id
        if pName and pName ~= "" then table.insert(pageNames, "'" .. pName:gsub("'", "\\'") .. "'") end
    end
   
    -- STEP 3: Get Details
    local playerDetails = {}
    if #pageNames > 0 then
        local details = cargo.query("Players", "_pageName, real_name, id", { where = "_pageName IN (" .. table.concat(pageNames, ",") .. ")" })
        if details then
            for _, d in ipairs(details) do
                playerDetails[d._pageName] = { realName = d.real_name, shortID = d.id }
            end
        end
    end
   
    -- STEP 4: Render
     local tbl = html.create('table'):addClass('flat-data-table sortable')
     local h = tbl:tag('tr')
     local h = tbl:tag('tr')
     h:tag('th'):wikitext('ID')
     h:tag('th'):wikitext('ID'); h:tag('th'):wikitext('Name'); h:tag('th'):wikitext('Role'); h:tag('th'):wikitext('Join Date'); h:tag('th'):wikitext('Leave Date')
    h:tag('th'):wikitext('Name')
    h:tag('th'):wikitext('Role')
    h:tag('th'):wikitext('Join Date')
    h:tag('th'):wikitext('Leave Date')
      
      
     for _, row in ipairs(results) do
     for _, row in ipairs(history) do
        local pName = row.player_id
        local details = playerDetails[pName] or {}
        local displayID = details.shortID
        if not displayID or displayID == "" then displayID = pName:gsub("^.*/", "") end
       
         local tr = tbl:tag('tr')
         local tr = tbl:tag('tr')
         tr:tag('td'):css('font-weight','bold'):wikitext('[[' .. row.id .. ']]')
         tr:tag('td'):addClass('t-id'):wikitext('[[' .. pName .. '|' .. displayID .. ']]')
         tr:tag('td'):wikitext(row.Name or "-")
         tr:tag('td'):wikitext(details.realName or "-")
         tr:tag('td'):wikitext(row.role or "-")
          
         tr:tag('td'):wikitext(row.join_date or "?")
        local rCell = tr:tag('td')
         tr:tag('td'):wikitext(row.leave_date or "?")
        if row.role and row.role ~= "" then rCell:tag('span'):addClass('t-role'):wikitext(row.role) else rCell:wikitext("-") end
       
         tr:tag('td'):addClass('t-date'):wikitext(row.join_date or "?")
         tr:tag('td'):addClass('t-date'):wikitext(row.leave_date or "?")
     end
     end
      
      
Line 246: Line 336:


-- ============================================================
-- ============================================================
-- MAIN 4: STAT HEADER (KEY METRICS)
-- MAIN 4: HISTORY
-- ============================================================
function p.history(frame)
    local args = getArgs(frame)
    local team = clean(args.team) or mw.title.getCurrentTitle().subpageText
    local results = cargo.query("StageStandings", "tournament, stage, totalpts, matchesplayed, wwcd, elimpts, lastmatchrank, result", {
        where = "team = '" .. team:gsub("'", "\\'") .. "'",
        orderBy = "tournament DESC",
        limit = 50
    })
   
    local root = html.create('div')
    root:wikitext('== Tournament Statistics ==')
   
    if #results > 0 then
        local tbl = root:tag('table'):addClass('modern-history-table')
        local thead = tbl:tag('thead'):tag('tr')
        thead:tag('th'):wikitext('Tournament'); thead:tag('th'):wikitext('Stage'); thead:tag('th'):wikitext('Rank')
        thead:tag('th'):wikitext('MP'); thead:tag('th'):wikitext('WWCD'); thead:tag('th'):wikitext('Elims'); thead:tag('th'):wikitext('Pts')
       
        for _, row in ipairs(results) do
            local tr = tbl:tag('tr')
            local res = (row.result or ""):lower()
            if res == "q" or res == "qualified" then tr:css('background-color', '#E9FFF0')
            elseif res == "e" or res == "eliminated" then tr:css('background-color', '#FFE9E9') end
           
            tr:tag('td'):css('font-weight','bold'):wikitext('[[' .. row.tournament .. ']]')
            tr:tag('td'):wikitext(row.stage)
            tr:tag('td'):css('font-weight','bold'):css('text-align','center'):wikitext('#' .. (row.lastmatchrank or '?'))
            tr:tag('td'):css('text-align','center'):wikitext(row.matchesplayed)
            tr:tag('td'):css('text-align','center'):wikitext(row.wwcd)
            tr:tag('td'):css('text-align','center'):wikitext(row.elimpts)
            tr:tag('td'):css('text-align','center'):css('font-weight','800'):wikitext(row.totalpts)
        end
    else root:wikitext("''No tournament data found for this team.''") end
    return tostring(root)
end
 
-- ============================================================
-- MAIN 5: TEAM ACHIEVEMENTS (Matches CSS & Logic)
-- ============================================================
-- ============================================================
function p.statHeader(frame)
function p.achievements(frame)
     local args = frame:getParent().args
     local args = getArgs(frame)
     local team = args.team or currentTitle.subpageText
     local team = clean(args.team) or currentTitle.subpageText
   
    -- STEP 1: Get Placements & Prizes
    local results = cargo.query(
        "PrizeMoney",
        "tournament, placement, prize, award",
        {
            where = "team = '" .. team:gsub("'", "\\'") .. "' AND (player='' OR player IS NULL)",
            orderBy = "prize DESC",
            limit = 50
        }
    )
      
      
    -- Get Earnings
     local root = html.create('div')
     local earnings = "0"
 
     local results = cargo.query("PrizeMoney", "SUM(prize)=total", { where = "team = '" .. team:gsub("'", "\\'") .. "' AND (player='' OR player IS NULL)" })
     if not results or #results == 0 then
     if results and #results > 0 and results[1].total then earnings = results[1].total end
        root:wikitext('<div style="font-style:italic; color:#64748b; padding:10px;">No achievements recorded.</div>')
        return tostring(root)
     end
      
      
     -- Get Rank
     -- STEP 2: Collect Tournament Names
     local rank = "N/A"
     local tourneyNames = {}
    local rRes = cargo.query("Krafton_Rankings", "rank", { where = "name = '" .. team:gsub("'", "\\'") .. "' AND type='Team'", limit = 1 })
    for _, row in ipairs(results) do
     if rRes and #rRes > 0 then rank = "#" .. rRes[1].rank end
        if row.tournament and row.tournament ~= "" then
            table.insert(tourneyNames, "'" .. row.tournament:gsub("'", "\\'") .. "'")
        end
     end
      
      
     -- HTML Build
     -- STEP 3: Fetch Date & Tier
     local bar = html.create('div'):addClass('team-dashboard-bar')
     local tDetails = {}
    if #tourneyNames > 0 then
        local tResults = cargo.query("Tournaments", "name, end_date, tier", { where = "name IN (" .. table.concat(tourneyNames, ",") .. ")" })
        if tResults then
            for _, t in ipairs(tResults) do tDetails[t.name] = { date = t.end_date, tier = t.tier } end
        end
    end
      
      
     -- Metric 1: Rank
     -- STEP 4: Render Table
     local m1 = bar:tag('div'):addClass('tdb-item')
     local tbl = root:tag('table'):addClass('achievements-table sortable')
    m1:tag('div'):addClass('tdb-label'):wikitext('Krafton Rank')
    local val1 = m1:tag('div'):addClass('tdb-value'):wikitext(rank)
    if rank ~= "N/A" then val1:addClass('highlight-gold') end
      
      
     -- Metric 2: Earnings
     local h = tbl:tag('tr')
     local m2 = bar:tag('div'):addClass('tdb-item')
     h:tag('th'):wikitext('Date')
     m2:tag('div'):addClass('tdb-label'):wikitext('Total Earnings')
     h:tag('th'):wikitext('Tier')
     m2:tag('div'):addClass('tdb-value'):wikitext('' .. formatCurrency(earnings):gsub("₹ ", ""):gsub('<[^>]+>','')) -- Strip HTML from currency for clean look
    h:tag('th'):wikitext('Tournament')
     h:tag('th'):wikitext('Place')
    h:tag('th'):css('text-align', 'right'):wikitext('Prize')
      
      
     -- Metric 3: Recent Form (Placeholder for now)
     for _, row in ipairs(results) do
    local m3 = bar:tag('div'):addClass('tdb-item')
        local tr = tbl:tag('tr')
    m3:tag('div'):addClass('tdb-label'):wikitext('Recent Form')
        local info = tDetails[row.tournament] or {}
    m3:tag('div'):addClass('tdb-value'):css('font-size','1em'):wikitext('Coming Soon')
       
        tr:tag('td'):addClass('ac-date'):wikitext(info.date or "-")
       
        -- UPDATED TIER CELL LOGIC (Using unified helper)
        local tierCell = tr:tag('td'):addClass('ac-tier')
        local tierClass = getTierClass(info.tier) -- Uses the new helper
       
        if info.tier and info.tier ~= "" then
            tierCell:tag('span'):addClass('tier-badge ' .. tierClass):wikitext(info.tier)  
        else
            tierCell:wikitext("-")
        end
       
        tr:tag('td'):css('font-weight', '600'):wikitext('[[' .. row.tournament .. ']]')
       
        local pCell = tr:tag('td'):addClass('ac-place')
        local rank = tonumber(row.placement) or 99
        local badgeClass = "place-def"
        local placeText = row.placement or "-"
        if rank == 1 then badgeClass = "place-1"; placeText = "1st"
        elseif rank == 2 then badgeClass = "place-2"; placeText = "2nd"
        elseif rank == 3 then badgeClass = "place-3"; placeText = "3rd"
        elseif placeText:match("^%d+$") then placeText = placeText .. "th"
        end
        pCell:tag('span'):addClass('place-badge ' .. badgeClass):wikitext(placeText)
       
        tr:tag('td'):addClass('ac-prize'):wikitext(formatCurrency(row.prize))
    end
      
      
     return tostring(bar)
     return tostring(root)
end
end


return p
return p

Latest revision as of 11:41, 1 February 2026

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

local p = {}
local cargo = mw.ext.cargo
local html = mw.html
local currentTitle = mw.title.getCurrentTitle()

-- ============================================================
-- HELPER: Argument Fetcher
-- ============================================================
local function getArgs(frame)
    local args = {}
    if frame:getParent() then
        for k, v in pairs(frame:getParent().args) do args[k] = v end
    end
    for k, v in pairs(frame.args) do args[k] = v end
    return args
end

-- ============================================================
-- HELPER: Sanitize Strings
-- ============================================================
local function clean(s)
    if not s then return nil end
    local cleaned = s:gsub("[\r\n]", ""):gsub("^%s*(.-)%s*$", "%1")
    if cleaned == "" then return nil end
    return cleaned
end

-- ============================================================
-- HELPER: Tier Class (MATCHES TOURNAMENT MODULE EXACTLY)
-- ============================================================
local function getTierClass(tier)
    if not tier then return "tier-def" end
    local t = tier:lower()
    -- Loose matching to catch "A Tier", "A-Tier", "Tier A"
    if string.find(t, "s") and string.find(t, "tier") then return "tier-s" end
    if string.find(t, "a") and string.find(t, "tier") then return "tier-a" end
    if string.find(t, "b") and string.find(t, "tier") then return "tier-b" end
    if string.find(t, "c") and string.find(t, "tier") then return "tier-c" end
    return "tier-def"
end

local function formatCurrency(amount)
    if not amount then return "0" end
    local n = tonumber(amount) or 0
    local formatted = tostring(n):reverse():gsub("(%d%d%d)(%d%d%d)","%1,%2"):reverse()
    return '<span class="indian-currency">₹ ' .. formatted .. '</span>'
end

local function getSocials(args)
    local container = html.create('div'):addClass('fib-socials')
    local hasSocials = false
    local platforms = {
        {arg='instagram', file='Icon_instagram.png', base='https://www.instagram.com/'},
        {arg='twitter',   file='Icon_twitter.png',   base='https://twitter.com/'},
        {arg='youtube',   file='Icon_youtube.png',   base='https://www.youtube.com/'},
        {arg='discord',   file='Icon_discord.png',   base='https://discord.gg/'},
        {arg='facebook',  file='Icon_facebook.png',  base='https://www.facebook.com/'},
        {arg='website',   file='Icon_website.png'}
    }
    for _, p in ipairs(platforms) do
        local val = args[p.arg]
        if val and val ~= "" then
            hasSocials = true
            local link
            if p.arg == 'website' then
                link = val
            elseif val:match("^https?://") then
                link = val
            else
                link = p.base .. val
            end
            container:wikitext('[[File:' .. p.file .. '|24px|link=' .. link .. '|class=social-img]]')
        end
    end

    if hasSocials then
        return tostring(container)
    end
    return ""
end

local function getInfoboxLogo(teamName, image, imageDark)
    local lightFile = (image ~= "" and image) or (teamName .. '.png')
    local darkFile = (imageDark ~= "" and imageDark) or (teamName .. '_dark.png')
    local hasLight = mw.title.new('File:' .. lightFile).exists
    local hasDark = mw.title.new('File:' .. darkFile).exists
    local container = html.create('div'):addClass('fib-image')
    local lSpan = container:tag('span'):addClass('logo-lightmode')
    if hasLight then lSpan:wikitext('[[File:' .. lightFile .. '|220px]]') else lSpan:wikitext('[[File:Shield_team.png|180px]]') end
    local dSpan = container:tag('span'):addClass('logo-darkmode')
    if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|220px]]') elseif hasLight then dSpan:wikitext('[[File:' .. lightFile .. '|220px]]') else dSpan:wikitext('[[File:Shield_team_dark.png|180px]]') end
    return tostring(container)
end

-- ============================================================
-- MAIN 1: TEAM INFOBOX
-- ============================================================
function p.infobox(frame)
    local args = getArgs(frame)
    local team = clean(args.name) or currentTitle.subpageText
    
    local root = html.create('div'):addClass('flat-infobox')
    root:tag('div'):addClass('fib-header'):tag('div'):addClass('fib-title'):wikitext(team)
    root:wikitext(getInfoboxLogo(team, clean(args.image), clean(args.image_dark)))
    
    local earnings = "0"
    if cargo and cargo.query then
        local results = cargo.query("PrizeMoney", "SUM(prize)=total", { where = "team = '" .. team:gsub("'", "\\'") .. "' AND (player='' OR player IS NULL)" })
        if results and #results > 0 and results[1].total then earnings = results[1].total end
    end
    
    local rankVal = "Unranked"
    if cargo and cargo.query then
        local rResults = cargo.query("Krafton_Rankings", "rank", { where = "name = '" .. team:gsub("'", "\\'") .. "' AND type='Team'", limit = 1 })
        if rResults and #rResults > 0 then rankVal = "#" .. rResults[1].rank end
    end
    
    local statusColor = "#333"
    local statusText = clean(args.status) or "Active"
    if args.status then
        local s = args.status:lower()
        if s == "active" then statusColor = "#16a34a" elseif s == "inactive" or s == "disbanded" then statusColor = "#dc2626" end
    end

    local grid1 = root:tag('div'):addClass('fib-grid')
    grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Status'):done():tag('div'):addClass('fib-value-sm'):css('color', statusColor):wikitext(statusText):done()
    grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Krafton Rank'):done():tag('div'):addClass('fib-value-sm'):wikitext(rankVal):done()

    local grid2 = root:tag('div'):addClass('fib-grid')
    grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Country'):done():tag('div'):addClass('fib-value-sm'):wikitext(clean(args.country) or 'TBD'):done()
    grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Tag'):done():tag('div'):addClass('fib-value-sm'):wikitext(clean(args.short_code) or '-'):done()

    if earnings and tonumber(earnings) and tonumber(earnings) > 0 then
        root:tag('div'):addClass('fib-prize'):tag('div'):addClass('fib-label-sm'):wikitext('Total Earnings'):done():tag('div'):addClass('fib-prize-val'):wikitext(formatCurrency(earnings)):done()
    end
    
    local list = root:tag('div'):addClass('fib-list')
    local function addRow(label, value)
        if value and value ~= "" then list:tag('div'):addClass('fib-row'):tag('div'):addClass('fib-label'):wikitext(label):done():tag('div'):addClass('fib-data'):wikitext(value):done() end
    end
    
    addRow('Display Name', clean(args.other_team))
    if args.sponsors then addRow('Sponsors', args.sponsors:gsub(",", "<br>")) end
    root:wikitext(getSocials(args))
    return tostring(root)
end

-- ============================================================
-- MAIN 2: HYBRID ROSTER (SORTED BY ROLE)
-- ============================================================
function p.roster(frame)
    local args = getArgs(frame)
    local team = clean(args.team) or currentTitle.subpageText
    
    -- 1. Fetch Database Players
    local dbPlayers = {}
    if cargo and cargo.query then
        local tables = "Players"
        local fields = "id, real_name, role, nationality, image, _pageName"
        local where = "current_team = '" .. team:gsub("'", "\\'") .. "' AND status='Active'"
        local results = cargo.query(tables, fields, { where = where })
        
        for _, row in ipairs(results) do
            dbPlayers[row.id] = {
                id = row.id,
                name = row.real_name,
                role = row.role,
                flag = clean(row.nationality),
                image = clean(row.image),
                link = row._pageName,
                source = "auto"
            }
        end
    end
    
    -- 2. Process Manual Inputs
    local finalRoster = {}
    for _, pData in pairs(dbPlayers) do table.insert(finalRoster, pData) end
    for i = 1, 10 do
        local mid = clean(args['player' .. i])
        if mid and mid ~= "" then
            if not dbPlayers[mid] then
                table.insert(finalRoster, {
                    id = mid,
                    name = clean(args['name' .. i]) or "",
                    role = clean(args['role' .. i]) or "Player",
                    flag = clean(args['flag' .. i]) or "India",
                    image = clean(args['image' .. i]) or "", 
                    link = mid, 
                    source = "manual"
                })
            end
        end
    end
    
    -- 3. Define Role Hierarchy & Colors
local roleConfig = {
        { key = "igl",      sort = 1, color = "#eab308" }, -- Gold
        { key = "filter",   sort = 2, color = "#14b8a6" }, -- Teal (New Position)
        { key = "entry",    sort = 3, color = "#f97316" }, -- Orange
        { key = "assault",  sort = 4, color = "#3b82f6" }, -- Blue
        { key = "fragger",  sort = 4, color = "#3b82f6" }, -- Blue
        { key = "support",  sort = 5, color = "#22c55e" }, -- Green
        { key = "medic",    sort = 5, color = "#22c55e" }, -- Green
        { key = "scout",    sort = 6, color = "#14b8a6" }, -- Teal
        { key = "sniper",   sort = 7, color = "#ef4444" }, -- Red
        { key = "coach",    sort = 8, color = "#a855f7" }, -- Purple
        { key = "analyst",  sort = 9, color = "#a855f7" }, -- Purple
        { key = "manager",  sort = 10, color = "#1f2937" } -- Dark Grey
    }
    
    -- 4. Assign Sort Priority & Color
    for _, player in ipairs(finalRoster) do
        local r = (player.role or ""):lower()
        player.sortOrder = 99
        player.color = "#64748b" -- Gray
        
        for _, config in ipairs(roleConfig) do
            if r:find(config.key) then
                player.sortOrder = config.sort
                player.color = config.color
                break 
            end
        end
    end
    
    -- 5. Sort
    table.sort(finalRoster, function(a, b)
        if a.sortOrder ~= b.sortOrder then
            return a.sortOrder < b.sortOrder 
        else
            return (a.id or ""):lower() < (b.id or ""):lower() 
        end
    end)
    
    -- 6. Render
    local grid = html.create('div'):addClass('hero-roster-grid')
    
    for _, player in ipairs(finalRoster) do
        local card = grid:tag('div'):addClass('hero-player-card')
        
        -- Header
        local header = card:tag('div'):addClass('hero-card-image')
        if player.image and player.image ~= "" then
            header:wikitext('[[File:' .. player.image .. '|link=' .. player.link .. ']]')
        else
            header:wikitext('[[File:Player_Placeholder.png|link=' .. player.link .. ']]')
        end
        
        -- Body
        local body = card:tag('div'):addClass('hero-card-body')
        
        body:tag('div'):addClass('hero-role-pill')
            :css('background-color', player.color)
            :wikitext(player.role or "Player")
            
        body:tag('div'):addClass('hero-player-id'):wikitext('[[' .. player.link .. '|' .. player.id .. ']]')
        if player.name and player.name ~= "" then
            body:tag('div'):addClass('hero-player-name'):wikitext(player.name)
        end
        
        if player.flag then
            local safeFlag = player.flag:gsub(" ", "_") 
            local flagFile = "Flag_" .. safeFlag .. ".png"
            body:tag('div'):addClass('hero-player-flag'):wikitext('[[File:' .. flagFile .. '|link=]] ' .. player.flag)
        end
    end
    
    return tostring(grid)
end

-- ============================================================
-- MAIN 3: FORMER PLAYERS LIST (NO JOIN + FLAT UI DESIGN)
-- ============================================================
function p.formerPlayers(frame)
    local args = getArgs(frame)
    local team = clean(args.team) or currentTitle.subpageText
    
    -- STEP 1: Get History
    local history = cargo.query(
        "Player_Former_Teams", 
        "player_id, role, join_date, leave_date", 
        {
            where = "team = '" .. team:gsub("'", "\\'") .. "' AND leave_date != ''",
            orderBy = "leave_date DESC",
            limit = 100
        }
    )
    
    if not history or #history == 0 then
        return '<div style="font-style:italic; color:#64748b; padding:10px;">No former players recorded.</div>'
    end
    
    -- STEP 2: Get Page Names
    local pageNames = {}
    for i, row in ipairs(history) do
        local pName = row.player_id
        if pName and pName ~= "" then table.insert(pageNames, "'" .. pName:gsub("'", "\\'") .. "'") end
    end
    
    -- STEP 3: Get Details
    local playerDetails = {}
    if #pageNames > 0 then
        local details = cargo.query("Players", "_pageName, real_name, id", { where = "_pageName IN (" .. table.concat(pageNames, ",") .. ")" })
        if details then
            for _, d in ipairs(details) do
                playerDetails[d._pageName] = { realName = d.real_name, shortID = d.id }
            end
        end
    end
    
    -- STEP 4: Render
    local tbl = html.create('table'):addClass('flat-data-table sortable')
    local h = tbl:tag('tr')
    h:tag('th'):wikitext('ID'); h:tag('th'):wikitext('Name'); h:tag('th'):wikitext('Role'); h:tag('th'):wikitext('Join Date'); h:tag('th'):wikitext('Leave Date')
    
    for _, row in ipairs(history) do
        local pName = row.player_id
        local details = playerDetails[pName] or {}
        local displayID = details.shortID
        if not displayID or displayID == "" then displayID = pName:gsub("^.*/", "") end
        
        local tr = tbl:tag('tr')
        tr:tag('td'):addClass('t-id'):wikitext('[[' .. pName .. '|' .. displayID .. ']]')
        tr:tag('td'):wikitext(details.realName or "-")
        
        local rCell = tr:tag('td')
        if row.role and row.role ~= "" then rCell:tag('span'):addClass('t-role'):wikitext(row.role) else rCell:wikitext("-") end
        
        tr:tag('td'):addClass('t-date'):wikitext(row.join_date or "?")
        tr:tag('td'):addClass('t-date'):wikitext(row.leave_date or "?")
    end
    
    return tostring(tbl)
end

-- ============================================================
-- MAIN 4: HISTORY
-- ============================================================
function p.history(frame)
    local args = getArgs(frame)
    local team = clean(args.team) or mw.title.getCurrentTitle().subpageText
    local results = cargo.query("StageStandings", "tournament, stage, totalpts, matchesplayed, wwcd, elimpts, lastmatchrank, result", {
        where = "team = '" .. team:gsub("'", "\\'") .. "'",
        orderBy = "tournament DESC",
        limit = 50
    })
    
    local root = html.create('div')
    root:wikitext('== Tournament Statistics ==')
    
    if #results > 0 then
        local tbl = root:tag('table'):addClass('modern-history-table')
        local thead = tbl:tag('thead'):tag('tr')
        thead:tag('th'):wikitext('Tournament'); thead:tag('th'):wikitext('Stage'); thead:tag('th'):wikitext('Rank')
        thead:tag('th'):wikitext('MP'); thead:tag('th'):wikitext('WWCD'); thead:tag('th'):wikitext('Elims'); thead:tag('th'):wikitext('Pts')
        
        for _, row in ipairs(results) do
            local tr = tbl:tag('tr')
            local res = (row.result or ""):lower()
            if res == "q" or res == "qualified" then tr:css('background-color', '#E9FFF0')
            elseif res == "e" or res == "eliminated" then tr:css('background-color', '#FFE9E9') end
            
            tr:tag('td'):css('font-weight','bold'):wikitext('[[' .. row.tournament .. ']]')
            tr:tag('td'):wikitext(row.stage)
            tr:tag('td'):css('font-weight','bold'):css('text-align','center'):wikitext('#' .. (row.lastmatchrank or '?'))
            tr:tag('td'):css('text-align','center'):wikitext(row.matchesplayed)
            tr:tag('td'):css('text-align','center'):wikitext(row.wwcd)
            tr:tag('td'):css('text-align','center'):wikitext(row.elimpts)
            tr:tag('td'):css('text-align','center'):css('font-weight','800'):wikitext(row.totalpts)
        end
    else root:wikitext("''No tournament data found for this team.''") end
    return tostring(root)
end

-- ============================================================
-- MAIN 5: TEAM ACHIEVEMENTS (Matches CSS & Logic)
-- ============================================================
function p.achievements(frame)
    local args = getArgs(frame)
    local team = clean(args.team) or currentTitle.subpageText
    
    -- STEP 1: Get Placements & Prizes
    local results = cargo.query(
        "PrizeMoney", 
        "tournament, placement, prize, award", 
        {
            where = "team = '" .. team:gsub("'", "\\'") .. "' AND (player='' OR player IS NULL)",
            orderBy = "prize DESC", 
            limit = 50
        }
    )
    
    local root = html.create('div')

    if not results or #results == 0 then
        root:wikitext('<div style="font-style:italic; color:#64748b; padding:10px;">No achievements recorded.</div>')
        return tostring(root)
    end
    
    -- STEP 2: Collect Tournament Names
    local tourneyNames = {}
    for _, row in ipairs(results) do
        if row.tournament and row.tournament ~= "" then
            table.insert(tourneyNames, "'" .. row.tournament:gsub("'", "\\'") .. "'")
        end
    end
    
    -- STEP 3: Fetch Date & Tier
    local tDetails = {}
    if #tourneyNames > 0 then
        local tResults = cargo.query("Tournaments", "name, end_date, tier", { where = "name IN (" .. table.concat(tourneyNames, ",") .. ")" })
        if tResults then
            for _, t in ipairs(tResults) do tDetails[t.name] = { date = t.end_date, tier = t.tier } end
        end
    end
    
    -- STEP 4: Render Table
    local tbl = root:tag('table'):addClass('achievements-table sortable')
    
    local h = tbl:tag('tr')
    h:tag('th'):wikitext('Date')
    h:tag('th'):wikitext('Tier')
    h:tag('th'):wikitext('Tournament')
    h:tag('th'):wikitext('Place')
    h:tag('th'):css('text-align', 'right'):wikitext('Prize')
    
    for _, row in ipairs(results) do
        local tr = tbl:tag('tr')
        local info = tDetails[row.tournament] or {}
        
        tr:tag('td'):addClass('ac-date'):wikitext(info.date or "-")
        
        -- UPDATED TIER CELL LOGIC (Using unified helper)
        local tierCell = tr:tag('td'):addClass('ac-tier')
        local tierClass = getTierClass(info.tier) -- Uses the new helper
        
        if info.tier and info.tier ~= "" then 
            tierCell:tag('span'):addClass('tier-badge ' .. tierClass):wikitext(info.tier) 
        else 
            tierCell:wikitext("-") 
        end
        
        tr:tag('td'):css('font-weight', '600'):wikitext('[[' .. row.tournament .. ']]')
        
        local pCell = tr:tag('td'):addClass('ac-place')
        local rank = tonumber(row.placement) or 99
        local badgeClass = "place-def"
        local placeText = row.placement or "-"
        if rank == 1 then badgeClass = "place-1"; placeText = "1st"
        elseif rank == 2 then badgeClass = "place-2"; placeText = "2nd"
        elseif rank == 3 then badgeClass = "place-3"; placeText = "3rd"
        elseif placeText:match("^%d+$") then placeText = placeText .. "th"
        end
        pCell:tag('span'):addClass('place-badge ' .. badgeClass):wikitext(placeText)
        
        tr:tag('td'):addClass('ac-prize'):wikitext(formatCurrency(row.prize))
    end
    
    return tostring(root)
end

return p