@ludiks/react
Version:
Complete React library for Ludiks gamification platform - includes SDK and ready-to-use components
39 lines (38 loc) • 11.6 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useLeaderboard } from '../../hooks/useLeaderboard';
import { cn } from '../../utils/cn';
export function Leaderboard({ period = 'all', limit = 10, showUserDetails = true, variant = 'table', autoRefresh = false, refreshInterval = 30000, className, colors = {}, }) {
const { data, loading, error, refetch } = useLeaderboard({
period,
limit,
autoRefresh,
refreshInterval,
});
const styles = {
primary: colors.primary || '#8b5cf6',
secondary: colors.secondary || '#06d6a0',
background: colors.background || '#ffffff',
text: colors.text || '#1f2937',
};
if (loading) {
return (_jsx("div", { className: cn('animate-pulse', className), children: _jsx("div", { className: "space-y-4", children: [...Array(Math.min(limit, 5))].map((_, i) => (_jsxs("div", { className: "flex items-center space-x-4 p-4 bg-gray-50 rounded-xl", children: [_jsx("div", { className: "h-12 w-12 bg-gray-200 rounded-full" }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx("div", { className: "h-4 bg-gray-200 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-gray-200 rounded w-1/2" })] }), _jsx("div", { className: "h-6 bg-gray-200 rounded w-20" })] }, i))) }) }));
}
if (error) {
return (_jsxs("div", { className: cn('text-center py-12', className), children: [_jsx("div", { className: "w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-4", children: _jsx("svg", { className: "w-8 h-8 text-red-500", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" }) }) }), _jsxs("p", { className: "text-red-600 mb-4 font-medium", children: ["Error loading leaderboard: ", error] }), _jsx("button", { onClick: refetch, className: "px-6 py-3 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors font-medium", children: "Try Again" })] }));
}
if (!data || data.length === 0) {
return (_jsxs("div", { className: cn('text-center py-12 text-gray-500', className), children: [_jsx("div", { className: "w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4", children: _jsx("svg", { className: "w-8 h-8 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) }), _jsx("p", { className: "font-medium", children: "No leaderboard data available" }), _jsx("p", { className: "text-sm mt-1", children: "Check back later for updates" })] }));
}
if (variant === 'podium') {
const podium = data.slice(0, 3);
const rest = data.slice(3);
return (_jsxs("div", { className: cn('w-full', className), children: [_jsxs("div", { className: "flex justify-center items-end mb-8 space-x-6", children: [podium[1] && (_jsxs("div", { className: "text-center transform translate-y-4", children: [_jsxs("div", { className: "relative mb-4", children: [podium[1].picture ? (_jsx("img", { src: podium[1].picture, alt: podium[1].fullName, className: "w-20 h-20 rounded-full mx-auto border-4 shadow-lg", style: { borderColor: '#c0c0c0' } })) : (_jsx("div", { className: "w-20 h-20 rounded-full mx-auto bg-gradient-to-br from-gray-300 to-gray-400 flex items-center justify-center text-gray-600 font-bold text-xl border-4 shadow-lg", style: { borderColor: '#c0c0c0' }, children: podium[1].fullName.charAt(0) })), _jsx("div", { className: "absolute -top-3 -right-3 w-10 h-10 rounded-full bg-gray-400 flex items-center justify-center text-white font-bold text-lg shadow-lg", children: "2" })] }), _jsxs("div", { className: "bg-gradient-to-br from-gray-50 to-gray-100 rounded-xl p-6 h-24 flex flex-col justify-center shadow-lg border border-gray-200", children: [_jsx("p", { className: "font-bold text-sm truncate", children: podium[1].fullName }), _jsxs("p", { className: "text-lg font-bold mt-1", style: { color: styles.primary }, children: [podium[1].totalPoints, " pts"] })] })] })), podium[0] && (_jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "relative mb-4", children: [podium[0].picture ? (_jsx("img", { src: podium[0].picture, alt: podium[0].fullName, className: "w-28 h-28 rounded-full mx-auto border-4 shadow-xl", style: { borderColor: '#ffd700' } })) : (_jsx("div", { className: "w-28 h-28 rounded-full mx-auto bg-gradient-to-br from-yellow-300 to-yellow-400 flex items-center justify-center text-white font-bold text-2xl border-4 shadow-xl", style: { borderColor: '#ffd700' }, children: podium[0].fullName.charAt(0) })), _jsx("div", { className: "absolute -top-3 -right-3 w-12 h-12 rounded-full bg-yellow-500 flex items-center justify-center text-white font-bold text-xl shadow-lg", children: "\uD83D\uDC51" })] }), _jsxs("div", { className: "bg-gradient-to-br from-yellow-50 to-yellow-100 rounded-xl p-6 h-32 flex flex-col justify-center shadow-xl border-2", style: { borderColor: '#ffd700' }, children: [_jsx("p", { className: "font-bold text-lg truncate", children: podium[0].fullName }), _jsxs("p", { className: "text-2xl font-bold mt-2", style: { color: styles.primary }, children: [podium[0].totalPoints, " pts"] })] })] })), podium[2] && (_jsxs("div", { className: "text-center transform translate-y-8", children: [_jsxs("div", { className: "relative mb-4", children: [podium[2].picture ? (_jsx("img", { src: podium[2].picture, alt: podium[2].fullName, className: "w-16 h-16 rounded-full mx-auto border-4 shadow-lg", style: { borderColor: '#cd7f32' } })) : (_jsx("div", { className: "w-16 h-16 rounded-full mx-auto bg-gradient-to-br from-amber-300 to-amber-400 flex items-center justify-center text-white font-bold text-lg border-4 shadow-lg", style: { borderColor: '#cd7f32' }, children: podium[2].fullName.charAt(0) })), _jsx("div", { className: "absolute -top-3 -right-3 w-8 h-8 rounded-full bg-amber-600 flex items-center justify-center text-white font-bold text-sm shadow-lg", children: "3" })] }), _jsxs("div", { className: "bg-gradient-to-br from-amber-50 to-amber-100 rounded-xl p-4 h-20 flex flex-col justify-center shadow-lg border border-amber-200", children: [_jsx("p", { className: "font-bold text-sm truncate", children: podium[2].fullName }), _jsxs("p", { className: "text-base font-bold mt-1", style: { color: styles.primary }, children: [podium[2].totalPoints, " pts"] })] })] }))] }), rest.length > 0 && (_jsx("div", { className: "space-y-3", children: rest.map((entry) => (_jsxs("div", { className: "flex items-center justify-between p-4 bg-white rounded-xl shadow-sm border border-gray-100 hover:shadow-md transition-shadow", children: [_jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("div", { className: "w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center text-sm font-bold text-gray-600", children: entry.rank }), _jsxs("div", { className: "flex items-center space-x-3", children: [entry.picture ? (_jsx("img", { src: entry.picture, alt: entry.fullName, className: "w-10 h-10 rounded-full" })) : (_jsx("div", { className: "w-10 h-10 rounded-full bg-gradient-to-br from-gray-300 to-gray-400 flex items-center justify-center text-xs font-bold text-white", children: entry.fullName.charAt(0) })), _jsx("span", { className: "font-semibold", children: entry.fullName })] })] }), _jsxs("div", { className: "font-bold text-lg", style: { color: styles.primary }, children: [entry.totalPoints, " pts"] })] }, entry.userId))) }))] }));
}
if (variant === 'minimal') {
return (_jsx("div", { className: cn('space-y-3', className), children: data.map((entry) => (_jsxs("div", { className: "flex items-center justify-between py-3 px-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors", children: [_jsxs("div", { className: "flex items-center space-x-4", children: [_jsxs("span", { className: "text-sm font-bold text-gray-500 w-8", children: ["#", entry.rank] }), _jsx("span", { className: "font-semibold", children: entry.fullName })] }), _jsx("span", { className: "font-bold text-lg", style: { color: styles.primary }, children: entry.totalPoints })] }, entry.userId))) }));
}
// Default: table variant
return (_jsx("div", { className: cn('w-full', className), children: _jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200 shadow-lg", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { style: { backgroundColor: styles.background }, children: _jsxs("tr", { children: [_jsx("th", { className: "px-6 py-4 text-left text-xs font-bold text-gray-500 uppercase tracking-wider", children: "Rank" }), _jsx("th", { className: "px-6 py-4 text-left text-xs font-bold text-gray-500 uppercase tracking-wider", children: "Player" }), _jsx("th", { className: "px-6 py-4 text-left text-xs font-bold text-gray-500 uppercase tracking-wider", children: "Points" }), showUserDetails && (_jsx("th", { className: "px-6 py-4 text-left text-xs font-bold text-gray-500 uppercase tracking-wider", children: "Streak" }))] }) }), _jsx("tbody", { className: "divide-y divide-gray-100", children: data.map((entry, index) => (_jsxs("tr", { className: index % 2 === 0 ? 'bg-white' : 'bg-gray-50 hover:bg-gray-100 transition-colors', children: [_jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: _jsx("div", { className: "flex items-center", children: entry.rank <= 3 ? (_jsx("div", { className: "w-10 h-10 rounded-full flex items-center justify-center text-white font-bold text-lg shadow-lg", style: {
backgroundColor: entry.rank === 1 ? '#ffd700' : entry.rank === 2 ? '#c0c0c0' : '#cd7f32'
}, children: entry.rank === 1 ? '👑' : entry.rank })) : (_jsxs("span", { className: "text-sm font-bold text-gray-500", children: ["#", entry.rank] })) }) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: _jsxs("div", { className: "flex items-center", children: [entry.picture ? (_jsx("img", { src: entry.picture, alt: entry.fullName, className: "w-12 h-12 rounded-full mr-4 shadow-sm" })) : (_jsx("div", { className: "w-12 h-12 rounded-full bg-gradient-to-br from-gray-300 to-gray-400 flex items-center justify-center text-white font-bold mr-4 shadow-sm", children: entry.fullName.charAt(0) })), _jsxs("div", { children: [_jsx("div", { className: "text-sm font-bold text-gray-900", children: entry.fullName }), showUserDetails && entry.email && (_jsx("div", { className: "text-sm text-gray-500", children: entry.email }))] })] }) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: _jsx("span", { className: "text-xl font-bold", style: { color: styles.primary }, children: entry.totalPoints }) }), showUserDetails && (_jsxs("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-gray-500", children: [_jsxs("div", { className: "flex items-center space-x-1", children: [_jsx("span", { children: "\uD83D\uDD25" }), _jsxs("span", { children: [entry.currentStreak, " days"] })] }), entry.longestStreak > entry.currentStreak && (_jsxs("div", { className: "text-xs text-gray-400 mt-1", children: ["Best: ", entry.longestStreak] }))] }))] }, entry.userId))) })] }) }) }));
}