11import React , { useState , useEffect } from 'react' ;
22import { useNavigate } from 'react-router-dom' ;
3- import { getAllAttemptSummaries } from '../../lib/api' ;
3+ import { getAllAttemptSummaries , getOtherUser } from '../../lib/api' ;
44// --- FIX: Import both time formatters ---
55import { formatDuration , formatTimeAgo } from '../../lib/timeFormatters' ;
6- // import useAuth from '../hooks/useAuth'; // Added useAuth to get the user
76
87// --- UI Imports from New UI ---
98import { Card } from "@/components/ui/card" ;
109import { Badge } from "@/components/ui/badge" ;
1110import {
12- User ,
13- Clock ,
14- Calendar // Added for "time ago"
11+ Calendar ,
12+ Code
1513} from "lucide-react" ;
1614// ------------------------------------
1715
@@ -22,17 +20,19 @@ interface SessionSummary {
2220 question_title : string ;
2321 question_difficulty : "Easy" | "Medium" | "Hard" ;
2422 partner_id : string ;
25- is_solved_successfully : boolean ;
23+ is_solved_successfully : boolean | null ;
2624 has_penalty : boolean ; // We need this to determine "Incomplete"
2725 started_at : string ;
28- time_taken_ms : number ;
26+ time_taken_ms : number | null ;
2927}
3028
3129const RecentSessionsList : React . FC < { userId : string , limit : number } > = ( { userId, limit } ) => {
3230 const navigate = useNavigate ( ) ;
3331 const [ sessions , setSessions ] = useState < SessionSummary [ ] > ( [ ] ) ;
3432 const [ loading , setLoading ] = useState ( true ) ;
33+ const [ usernames , setUsernames ] = useState < Map < string , string > > ( new Map ( ) ) ;
3534
35+ // Fetch sessions
3636 useEffect ( ( ) => {
3737 if ( ! userId ) return ;
3838
@@ -53,6 +53,39 @@ const RecentSessionsList: React.FC<{ userId: string, limit: number }> = ({ userI
5353 fetchRecent ( ) ;
5454 } , [ userId , limit ] ) ;
5555
56+ // Fetch usernames for all unique partner IDs
57+ useEffect ( ( ) => {
58+ if ( sessions . length === 0 ) return ;
59+
60+ const fetchUsernames = async ( ) => {
61+ const uniquePartnerIds = [ ...new Set ( sessions . map ( s => s . partner_id ) . filter ( id => id ) ) ] ;
62+ const usernameMap = new Map < string , string > ( ) ;
63+
64+ // Fetch usernames in parallel
65+ await Promise . allSettled (
66+ uniquePartnerIds . map ( async ( partnerId ) => {
67+ try {
68+ const response = await getOtherUser ( partnerId ) ;
69+ // getOtherUser returns { data: { username, ... } }
70+ if ( response ?. data ?. username ) {
71+ usernameMap . set ( partnerId , response . data . username ) ;
72+ } else {
73+ usernameMap . set ( partnerId , partnerId ) ;
74+ }
75+ } catch ( error ) {
76+ console . error ( `Failed to fetch username for partner ${ partnerId } :` , error ) ;
77+ // Keep partner_id as fallback
78+ usernameMap . set ( partnerId , partnerId ) ;
79+ }
80+ } )
81+ ) ;
82+
83+ setUsernames ( usernameMap ) ;
84+ } ;
85+
86+ fetchUsernames ( ) ;
87+ } , [ sessions ] ) ;
88+
5689 const handleSessionClick = ( questionId : string ) => {
5790 // Navigate to the detail page for that question
5891 navigate ( `/history/attempts/${ questionId } ` ) ;
@@ -68,56 +101,100 @@ const RecentSessionsList: React.FC<{ userId: string, limit: number }> = ({ userI
68101
69102 // --- This is the new UI, adapted to the REAL API data ---
70103 return (
71- < div className = "space-y-4 " >
104+ < div className = "space-y-3 " >
72105 { /* The title "Recent Sessions" is in your userProfile.tsx, so we don't repeat it here */ }
73- < div className = "space-y-3" >
74- { sessions . map ( ( session ) => (
106+ { sessions . map ( ( session ) => {
107+ const statusText = session . is_solved_successfully === true ? "Passed" : ( session . has_penalty ? "Incomplete" : "Failed" ) ;
108+ const statusColor = session . is_solved_successfully === true ? 'bg-green-500' : ( session . has_penalty ? 'bg-orange-500' : 'bg-red-500' ) ;
109+ const difficultyColors : Record < string , { bg : string ; text : string } > = {
110+ Easy : { bg : 'bg-green-100' , text : 'text-green-800' } ,
111+ Medium : { bg : 'bg-yellow-100' , text : 'text-yellow-800' } ,
112+ Hard : { bg : 'bg-red-100' , text : 'text-red-800' }
113+ } ;
114+ const difficultyStyle = difficultyColors [ session . question_difficulty ] || difficultyColors . Medium ;
115+
116+ return (
75117 < Card
76118 key = { session . session_id }
77- className = "p-4 shadow-soft hover:shadow-card transition-smooth cursor-pointer"
119+ className = "p-4 cursor-pointer"
120+ style = { {
121+ background : 'white' ,
122+ borderRadius : '12px' ,
123+ boxShadow : '0 2px 8px rgba(0, 0, 0, 0.1)' ,
124+ transition : 'all 0.3s ease' ,
125+ border : '1px solid #e5e7eb'
126+ } }
127+ onMouseEnter = { ( e ) => {
128+ e . currentTarget . style . boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)' ;
129+ } }
130+ onMouseLeave = { ( e ) => {
131+ e . currentTarget . style . boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)' ;
132+ } }
78133 onClick = { ( ) => handleSessionClick ( session . question_id ) }
79134 >
80- < div className = "flex items-center justify-between" >
81- < div className = "space-y-1" >
82- < div className = "flex items-center gap-2" >
135+ < div className = "flex items-center gap-4" >
136+ { /* Left: Code Icon */ }
137+ < div
138+ className = "flex-shrink-0 flex items-center justify-center"
139+ style = { {
140+ width : '48px' ,
141+ height : '48px' ,
142+ backgroundColor : '#addaf7' ,
143+ borderRadius : '8px'
144+ } }
145+ >
146+ < Code className = "h-6 w-6 text-white" style = { { strokeWidth : 2.5 } } />
147+ </ div >
148+
149+ { /* Middle: Topic, Difficulty, Partner, Time */ }
150+ < div className = "flex-1 space-y-1" >
151+ { /* Topic in bold */ }
152+ < div className = "font-bold text-base text-gray-900" >
153+ { session . question_title }
154+ </ div >
155+
156+ { /* Difficulty badge and Partner */ }
157+ < div className = "flex items-center gap-2 flex-wrap" >
83158 < Badge
84- variant = { session . question_difficulty } // Use Easy, Medium, Hard variants
159+ className = { `${ difficultyStyle . bg } ${ difficultyStyle . text } border-0 font-medium` }
160+ style = { { fontSize : '12px' , padding : '2px 8px' } }
85161 >
86162 { session . question_difficulty }
87163 </ Badge >
88- { /* API provides question_title, not topic */ }
89- < span className = "font-medium text-sm" > { session . question_title } </ span >
164+ < span className = "text-sm text-gray-500" >
165+ with { usernames . get ( session . partner_id ) || session . partner_id }
166+ </ span >
90167 </ div >
91- < div className = "flex items-center gap-4 text-sm text-muted-foreground" >
92- < div className = "flex items-center gap-1" >
93- < User className = "h-3 w-3" />
94- { session . partner_id }
95- </ div >
168+
169+ { /* Time taken and Time ago */ }
170+ < div className = "flex items-center gap-4 text-sm text-gray-500" >
171+ { session . time_taken_ms && (
172+ < span > { formatDuration ( session . time_taken_ms ) } </ span >
173+ ) }
96174 < div className = "flex items-center gap-1" >
97- < Clock className = "h-3 w-3" />
98- { /* API provides time_taken_ms, format it */ }
99- { formatDuration ( session . time_taken_ms ) }
100- </ div >
101- { /* API provides started_at, let's show time ago */ }
102- < div className = "flex items-center gap-1" >
103175 < Calendar className = "h-3 w-3" />
104- { formatTimeAgo ( session . started_at ) }
176+ < span > { formatTimeAgo ( session . started_at ) } </ span >
105177 </ div >
106178 </ div >
107179 </ div >
108-
109- { /* API provides booleans, we derive the status */ }
110- < Badge className = {
111- session . is_solved_successfully ? 'bg-green-500 text-white' : // "Passed" (blue)
112- session . has_penalty ? 'bg-orange-500 text-white' : // "Incomplete" (gray)
113- 'bg-red-500 text-white' // "Failed" (red)
114- } >
115- { session . is_solved_successfully ? "Passed" : ( session . has_penalty ? "Incomplete" : "Failed" ) }
116- </ Badge >
180+
181+ { /* Right: Status Badge */ }
182+ < div className = "flex-shrink-0" >
183+ < Badge
184+ className = { `${ statusColor } text-white border-0 font-medium` }
185+ style = { {
186+ fontSize : '13px' ,
187+ padding : '4px 12px' ,
188+ borderRadius : '9999px'
189+ } }
190+ >
191+ { statusText }
192+ </ Badge >
193+ </ div >
117194 </ div >
118195 </ Card >
119- ) ) }
120- </ div >
196+ ) ;
197+ } ) }
121198 </ div >
122199 ) ;
123200} ;
0 commit comments