@@ -24,11 +24,24 @@ type AttendanceRecord = {
2424 total_hours : number | null
2525 status ?: string // 'Complete' | 'Pending'
2626 created_at : string
27+ type : 'attendance'
28+ }
29+
30+ type LeaveRecord = {
31+ id : string
32+ user_id : string
33+ leave_type : string
34+ start_date : string
35+ end_date : string
36+ reason : string
37+ status : 'pending' | 'approved' | 'rejected'
38+ created_at : string
39+ type : 'leave'
2740}
2841
2942export default function StaffHistoryPage ( ) {
3043 const { user, loading : authLoading } = useAuth ( )
31- const [ history , setHistory ] = useState < AttendanceRecord [ ] > ( [ ] )
44+ const [ history , setHistory ] = useState < ( AttendanceRecord | LeaveRecord ) [ ] > ( [ ] )
3245 const [ loading , setLoading ] = useState ( true )
3346 const [ stats , setStats ] = useState ( {
3447 totalHours : 0 ,
@@ -43,20 +56,38 @@ export default function StaffHistoryPage() {
4356
4457 const fetchData = async ( ) => {
4558 try {
46- const { data, error } = await supabase
59+ // Fetch Attendance
60+ const { data : attendanceData , error : attendanceError } = await supabase
4761 . from ( "attendance_logs" )
4862 . select ( "*" )
4963 . eq ( "user_id" , user . id )
50- . order ( "check_in" , { ascending : false } )
5164
52- if ( error ) throw error
65+ if ( attendanceError ) throw attendanceError
66+
67+ // Fetch Leaves
68+ const { data : leaveData , error : leaveError } = await supabase
69+ . from ( "leave_requests" )
70+ . select ( "*" )
71+ . eq ( "user_id" , user . id )
72+ . neq ( "status" , "rejected" ) // Only show pending/approved
73+
74+ if ( leaveError ) throw leaveError
5375
54- const records = data || [ ]
55- setHistory ( records )
76+ const attendanceRecords : AttendanceRecord [ ] = ( attendanceData || [ ] ) . map ( r => ( { ...r , type : 'attendance' } ) )
77+ const leaveRecords : LeaveRecord [ ] = ( leaveData || [ ] ) . map ( r => ( { ...r , type : 'leave' } ) )
78+
79+ // Merge and Sort
80+ const mergedRecords = [ ...attendanceRecords , ...leaveRecords ] . sort ( ( a , b ) => {
81+ const dateA = a . type === 'attendance' ? new Date ( a . check_in ) : new Date ( a . start_date )
82+ const dateB = b . type === 'attendance' ? new Date ( b . check_in ) : new Date ( b . start_date )
83+ return dateB . getTime ( ) - dateA . getTime ( ) // Descending
84+ } )
5685
57- // Calculate stats
58- const totalHours = records . reduce ( ( acc , curr ) => acc + ( curr . total_hours || 0 ) , 0 )
59- const daysPresent = records . length
86+ setHistory ( mergedRecords )
87+
88+ // Calculate stats (only from attendance)
89+ const totalHours = attendanceRecords . reduce ( ( acc , curr ) => acc + ( curr . total_hours || 0 ) , 0 )
90+ const daysPresent = attendanceRecords . length
6091 const averageHours = daysPresent > 0 ? totalHours / daysPresent : 0
6192
6293 setStats ( {
@@ -92,17 +123,9 @@ export default function StaffHistoryPage() {
92123 Attendance < span className = "text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-400" > History</ span >
93124 </ h1 >
94125 < p className = "text-zinc-400" >
95- View and track your past attendance records.
126+ View and track your past attendance and leave records.
96127 </ p >
97128 </ div >
98- { /* <div className="flex gap-2">
99- <Button variant="outline" className="border-zinc-800 bg-zinc-900/50 hover:bg-zinc-800 text-zinc-300">
100- <Filter className="mr-2 h-4 w-4" /> Filter
101- </Button>
102- <Button variant="outline" className="border-zinc-800 bg-zinc-900/50 hover:bg-zinc-800 text-zinc-300">
103- <Download className="mr-2 h-4 w-4" /> Export
104- </Button>
105- </div> */ }
106129 </ header >
107130
108131 { /* Stats Overview */ }
@@ -167,55 +190,86 @@ export default function StaffHistoryPage() {
167190 { history . length === 0 ? (
168191 < tr >
169192 < td colSpan = { 5 } className = "px-6 py-12 text-center text-zinc-500" >
170- No attendance records found.
193+ No records found.
171194 </ td >
172195 </ tr >
173196 ) : (
174197 history . map ( ( record ) => {
175- const date = new Date ( record . check_in ) . toLocaleDateString ( undefined , {
176- weekday : 'short' ,
177- year : 'numeric' ,
178- month : 'short' ,
179- day : 'numeric'
180- } )
181- const checkInTime = new Date ( record . check_in ) . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } )
182- const checkOutTime = record . check_out
183- ? new Date ( record . check_out ) . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } )
184- : '-'
185-
186- const isComplete = ! ! record . check_out
187-
188- return (
189- < tr key = { record . id } className = "group hover:bg-zinc-800/30 transition-colors" >
190- < td className = "px-6 py-4 text-zinc-300 font-medium" > { date } </ td >
191- < td className = "px-6 py-4 text-zinc-400" > { checkInTime } </ td >
192- < td className = "px-6 py-4 text-zinc-400" > { checkOutTime } </ td >
193- < td className = "px-6 py-4" >
194- < span className = { `px-2.5 py-1 rounded font-mono text-xs font-medium ${ record . total_hours && record . total_hours >= 8
198+ if ( record . type === 'leave' ) {
199+ // Render Leave Row
200+ const r = record as LeaveRecord
201+ const date = new Date ( r . start_date ) . toLocaleDateString ( undefined , {
202+ weekday : 'short' ,
203+ year : 'numeric' ,
204+ month : 'short' ,
205+ day : 'numeric'
206+ } )
207+ return (
208+ < tr key = { r . id } className = "group hover:bg-zinc-800/30 transition-colors bg-blue-500/5 border-l-2 border-blue-500/20" >
209+ < td className = "px-6 py-4 text-zinc-300 font-medium" > { date } </ td >
210+ < td className = "px-6 py-4 text-zinc-500" > -</ td >
211+ < td className = "px-6 py-4 text-zinc-500" > -</ td >
212+ < td className = "px-6 py-4" >
213+ < span className = "px-2.5 py-1 rounded font-mono text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/20" >
214+ { r . leave_type } Leave
215+ </ span >
216+ </ td >
217+ < td className = "px-6 py-4" >
218+ < div className = "flex items-center gap-1.5 text-xs font-medium text-blue-400" >
219+ < Calendar className = "w-4 h-4" />
220+ On Leave
221+ </ div >
222+ </ td >
223+ </ tr >
224+ )
225+ } else {
226+ // Render Attendance Row
227+ const r = record as AttendanceRecord
228+ const date = new Date ( r . check_in ) . toLocaleDateString ( undefined , {
229+ weekday : 'short' ,
230+ year : 'numeric' ,
231+ month : 'short' ,
232+ day : 'numeric'
233+ } )
234+ const checkInTime = new Date ( r . check_in ) . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } )
235+ const checkOutTime = r . check_out
236+ ? new Date ( r . check_out ) . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } )
237+ : '-'
238+
239+ const isComplete = ! ! r . check_out
240+
241+ return (
242+ < tr key = { r . id } className = "group hover:bg-zinc-800/30 transition-colors" >
243+ < td className = "px-6 py-4 text-zinc-300 font-medium" > { date } </ td >
244+ < td className = "px-6 py-4 text-zinc-400" > { checkInTime } </ td >
245+ < td className = "px-6 py-4 text-zinc-400" > { checkOutTime } </ td >
246+ < td className = "px-6 py-4" >
247+ < span className = { `px-2.5 py-1 rounded font-mono text-xs font-medium ${ r . total_hours && r . total_hours >= 8
195248 ? "bg-green-500/10 text-green-400 border border-green-500/20"
196249 : "bg-blue-500/10 text-blue-400 border border-blue-500/20"
197- } `} >
198- { record . total_hours ? `${ record . total_hours . toFixed ( 2 ) } h` : '-' }
199- </ span >
200- </ td >
201- < td className = "px-6 py-4" >
202- < div className = { `flex items-center gap-1.5 text-xs font-medium ${ isComplete ? "text-green-400" : "text-yellow-400"
203- } `} >
204- { isComplete ? (
205- < >
206- < CheckCircle2 className = "w-4 h-4" />
207- Completed
208- </ >
209- ) : (
210- < >
211- < Clock className = "w-4 h-4" />
212- Active
213- </ >
214- ) }
215- </ div >
216- </ td >
217- </ tr >
218- )
250+ } `} >
251+ { r . total_hours ? `${ r . total_hours . toFixed ( 2 ) } h` : '-' }
252+ </ span >
253+ </ td >
254+ < td className = "px-6 py-4" >
255+ < div className = { `flex items-center gap-1.5 text-xs font-medium ${ isComplete ? "text-green-400" : "text-yellow-400"
256+ } `} >
257+ { isComplete ? (
258+ < >
259+ < CheckCircle2 className = "w-4 h-4" />
260+ Completed
261+ </ >
262+ ) : (
263+ < >
264+ < Clock className = "w-4 h-4" />
265+ Active
266+ </ >
267+ ) }
268+ </ div >
269+ </ td >
270+ </ tr >
271+ )
272+ }
219273 } )
220274 ) }
221275 </ tbody >
0 commit comments