@@ -32,35 +32,58 @@ const FALLBACK_BADGES = [
3232/* ── XP Level helper ─────────────────────────────────────── */
3333const XP_PER_LEVEL = 500 ;
3434const getLevel = ( xp ) => Math . floor ( xp / XP_PER_LEVEL ) + 1 ;
35- const getLevelPct = ( xp ) => ( ( xp % XP_PER_LEVEL ) / XP_PER_LEVEL ) * 100 ;
3635
3736/* ── Animated XP bar ─────────────────────────────────────── */
38- const XPBar = ( { xp } ) => {
37+ const XPBar = ( { xp, loginXp = 0 , challengeXp = 0 , loginCount = 0 } ) => {
3938 const ref = useRef ( null ) ;
4039 const inView = useInView ( ref , { once : true } ) ;
41- const pct = getLevelPct ( xp ) ;
40+ const currentLevelXp = xp % XP_PER_LEVEL ;
41+ const pct = ( currentLevelXp / XP_PER_LEVEL ) * 100 ;
4242 const lvl = getLevel ( xp ) ;
43+
44+ const loginRatio = xp > 0 ? loginXp / xp : 0 ;
45+
4346 return (
44- < div ref = { ref } className = "space-y-1.5" >
47+ < div ref = { ref } className = "space-y-1.5 relative group " >
4548 < div className = "flex items-center justify-between text-[10px] font-black uppercase tracking-widest" >
4649 < span className = "text-tertiary" > Level { lvl } </ span >
47- < span style = { { color : "rgb(var(--accent-rgb))" } } > { xp } XP</ span >
50+ < span style = { { color : "rgb(var(--accent-rgb))" } } > { currentLevelXp } / { XP_PER_LEVEL } XP</ span >
4851 </ div >
49- < div className = "h-1.5 rounded-full bg-black/[0.06] dark:bg-white/[0.06] overflow-hidden" >
52+
53+ { /* XP Breakdown Tooltip */ }
54+ < div className = "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 w-max bg-black/90 dark:bg-white/90 text-white dark:text-black text-[10px] font-bold p-2 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity z-50 shadow-xl shadow-black/20 text-center flex flex-col gap-1 pointer-events-none" >
55+ < div className = "flex justify-between gap-4" >
56+ < span className = "text-[#3b82f6]" > Daily Login XP:</ span >
57+ < span > { loginXp } XP ({ loginCount } days)</ span >
58+ </ div >
59+ < div className = "flex justify-between gap-4" >
60+ < span className = "text-[#ec4899]" > Challenges XP:</ span >
61+ < span > { challengeXp } XP</ span >
62+ </ div >
63+ < div className = "mt-1 pt-1 border-t border-white/20 dark:border-black/20 flex justify-between gap-4" >
64+ < span className = "text-white/60 dark:text-black/60" > Total XP:</ span >
65+ < span > { xp } XP</ span >
66+ </ div >
67+ { /* Little triangle pointing down */ }
68+ < div className = "absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-black/90 dark:border-t-white/90" />
69+ </ div >
70+
71+ < div className = "h-1.5 rounded-full bg-black/[0.06] dark:bg-white/[0.06] overflow-hidden flex" >
5072 < motion . div
5173 className = "h-full rounded-full"
5274 style = { {
53- background : " linear-gradient(90deg, rgba(var(--accent-rgb),0.9), rgba(168,85,247,0.9))" ,
54- boxShadow : " 0 0 10px rgba(var(--accent-rgb), 0.5)" ,
75+ background : ` linear-gradient(90deg, #3b82f6 0%, #a855f7 ${ loginRatio * 100 } %, #ec4899 100%)` ,
76+ boxShadow : ` 0 0 10px rgba(168,85,247, 0.5)`
5577 } }
5678 initial = { { width : 0 } }
5779 animate = { { width : inView ? `${ pct } %` : 0 } }
5880 transition = { { duration : 1.4 , ease : "easeOut" } }
5981 />
6082 </ div >
61- < p className = "text-[10px] text-tertiary" >
62- { XP_PER_LEVEL - ( xp % XP_PER_LEVEL ) } XP to Level { lvl + 1 }
63- </ p >
83+ < div className = "flex justify-between text-[10px] text-tertiary" >
84+ < span > { XP_PER_LEVEL - currentLevelXp } XP to Level { lvl + 1 } </ span >
85+ < span className = "font-semibold text-secondary" > Total: { xp } XP</ span >
86+ </ div >
6487 </ div >
6588 ) ;
6689} ;
@@ -115,6 +138,9 @@ const ProfileSidebar = ({ user, summary, profile, badges }) => {
115138 const streak = profile ?. streak ?? 0 ;
116139 const maxStreak = profile ?. maxStreak ?? 0 ;
117140 const xp = profile ?. stats ?. totalPoints ?? profile ?. totalPoints ?? 0 ;
141+ const loginXp = profile ?. stats ?. loginXp ?? profile ?. loginXp ?? 0 ;
142+ const challengeXp = profile ?. stats ?. challengeXp ?? profile ?. challengeXp ?? 0 ;
143+ const loginCount = profile ?. stats ?. loginCount ?? profile ?. loginCount ?? 0 ;
118144 const rank = profile ?. rank ?? "—" ;
119145 const roleName = user ?. customTitle || ( user ?. role === "admin" ? "Admin"
120146 : user ?. role === "clan-chief" ? "Clan Chief"
@@ -295,7 +321,7 @@ const ProfileSidebar = ({ user, summary, profile, badges }) => {
295321 </ div >
296322
297323 { /* XP Level bar */ }
298- < XPBar xp = { xp } />
324+ < XPBar xp = { xp } loginXp = { loginXp } challengeXp = { challengeXp } loginCount = { loginCount } />
299325
300326 { /* Divider */ }
301327 < div className = "h-px bg-black/[0.08] dark:bg-white/[0.08]" />
0 commit comments