import { useEffect, useState } from 'react'; import { Link } from 'react-router'; import { Spinner } from 'react-bootstrap'; import { signedGet, isSuccess } from '@/api/client'; import { asArray, rankRoleId, rankRoleName, rankRolePillLabel, userInitials } from '@/views/dashboard/helpers'; import EmptyChart from '@/views/dashboard/EmptyChart'; function podiumUsersFromRankRole(rankRole) { return asArray(rankRole?.users) .slice(0, 3) .map((row) => { const info = row.user || {}; const name = String(info.name || '').trim(); return { name, initials: userInitials(name), avatar: info.avatar || '', score: Number.isFinite(Number(row.score)) ? Number(row.score) : 0, }; }); } function Podium({ users }) { const slots = [users[1] || null, users[0] || null, users[2] || null]; const ranks = [2, 1, 3]; return (
{slots.map((user, index) => { const rank = ranks[index]; return (
{user ? ( <>
{rank === 1 ? ( ) : null}
{user.avatar && !String(user.avatar).includes('ui-avatars.com') ? ( ) : ( user.initials )}
{rank}
{user.name}
{user.score}
) : ( <>
-
-
)}
); })}
); } function LeaderboardCard({ item }) { const [activeIndex, setActiveIndex] = useState(0); const pills = item.pills || []; const active = pills[activeIndex] || pills[0]; const users = active?.podium_users || item.podium_users || []; const detailsUrl = active?.url || item.details_url || '#'; return (

{item.title}

{item.interval_label || '—'}

View details
{pills.length ? (
{pills.map((pill, index) => ( ))}
) : null}
); } export default function MilestoneTeamLeaderboard({ widget }) { const [items, setItems] = useState(null); useEffect(() => { const load = async () => { const response = await signedGet('reports', 'roles_leaderboard/list', {}, { timeout: 120000 }); if (!isSuccess(response)) { setItems([]); return; } let leaderboards = response.data; if (leaderboards?.items) leaderboards = leaderboards.items; leaderboards = asArray(leaderboards); const mapped = leaderboards.map((board) => { const rankRoles = asArray(board.rank_roles); const pills = rankRoles.map((rankRole, index) => { const limit = Number(rankRole.limit) > 0 ? Number(rankRole.limit) : 10; const roleId = rankRoleId(rankRole); return { label: rankRolePillLabel(rankRole.title, limit, rankRoleName(rankRole)), url: `/leaderboard/dashboard?id=${encodeURIComponent(board.id || '')}&role=${encodeURIComponent(roleId)}`, podium_users: podiumUsersFromRankRole(rankRole), active: index === 0, }; }); const start = board.validity_start || ''; const end = board.validity_end || ''; return { id: board.id, title: board.name || widget.title || 'Leaderboard', interval_label: `${start}${start && end ? ' – ' : ''}${end}`.trim(), details_url: pills[0]?.url || `/leaderboard/dashboard?id=${encodeURIComponent(board.id || '')}`, podium_users: pills[0]?.podium_users || [], pills, }; }); setItems(mapped); }; load(); }, [widget.title]); return (

{widget.title || 'Leaderboard'}

{items === null ? (

Loading leaderboards...

) : items.length === 0 ? ( ) : (
{items.map((item) => ( ))}
)}
); }