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 ? (
) : items.length === 0 ? (
) : (
{items.map((item) => (
))}
)}
);
}