@@ -49,7 +49,7 @@ <h2 class="font-semibold">{{ _('me.rentals_title') }}</h2>
4949 < tr class ="border-t hover:bg-gray-50 ">
5050 < td class ="px-4 py-2 font-medium " x-text ="r.item_name "> </ td >
5151 < td class ="px-4 py-2 text-xs text-gray-400 text-right "
52- x-text ="r.rented_at ? r.rented_at.substring(0,16).replace('T',' ') : '' "> </ td >
52+ x-text ="fmtDateTime( r.rented_at) "> </ td >
5353 </ tr >
5454 </ template >
5555 </ tbody >
@@ -90,6 +90,53 @@ <h2 class="font-semibold">{{ _('me.machines_title') }}</h2>
9090
9191 </ div >
9292
93+ <!-- Machine Session History -->
94+ < div class ="bg-white rounded-lg shadow mb-6 ">
95+ < div class ="px-5 py-4 border-b ">
96+ < h2 class ="font-semibold "> {{ _('me.sessions_title') }}</ h2 >
97+ </ div >
98+ < div class ="overflow-x-auto ">
99+ < table class ="w-full text-sm ">
100+ < thead class ="bg-gray-50 text-gray-500 text-xs uppercase ">
101+ < tr >
102+ < th class ="px-4 py-2 text-left "> {{ _('me.sessions_machine') }}</ th >
103+ < th class ="px-4 py-2 text-left "> {{ _('machines.col_start') }}</ th >
104+ < th class ="px-4 py-2 text-left "> {{ _('machines.col_duration') }}</ th >
105+ < th class ="px-4 py-2 text-right "> {{ _('machines.col_cost') }}</ th >
106+ </ tr >
107+ </ thead >
108+ < tbody >
109+ < template x-if ="loadingSessions ">
110+ < tr > < td colspan ="4 " class ="px-4 py-6 text-center text-gray-400 "> Loading…</ td > </ tr >
111+ </ template >
112+ < template x-if ="!loadingSessions && sessions.length === 0 ">
113+ < tr > < td colspan ="4 " class ="px-4 py-6 text-center text-gray-400 "> {{ _('me.sessions_empty') }}</ td > </ tr >
114+ </ template >
115+ < template x-for ="s in sessions " :key ="s.id ">
116+ < tr class ="border-t hover:bg-gray-50 ">
117+ < td class ="px-4 py-2 font-medium " x-text ="s.machine_name "> </ td >
118+ < td class ="px-4 py-2 text-xs text-gray-500 whitespace-nowrap " x-text ="fmtDateTime(s.start_time) "> </ td >
119+ < td class ="px-4 py-2 text-xs text-gray-500 ">
120+ < template x-if ="s.end_time === null ">
121+ < span class ="bg-green-100 text-green-700 rounded px-1.5 py-0.5 "> {{ _('machines.history_active') }}</ span >
122+ </ template >
123+ < template x-if ="s.end_time !== null ">
124+ < span x-text ="fmtDuration(s.duration_seconds) "> </ span >
125+ </ template >
126+ </ td >
127+ < td class ="px-4 py-2 text-right tabular-nums text-xs "
128+ x-text ="parseFloat(s.total_cost).toFixed(2) + ' €' "> </ td >
129+ </ tr >
130+ </ template >
131+ </ tbody >
132+ </ table >
133+ </ div >
134+ < div class ="mt-3 px-5 pb-3 text-center " x-show ="sessionHasMore && !loadingSessions ">
135+ < button @click ="loadSessions() "
136+ class ="text-sm text-blue-600 hover:underline "> {{ _('machines.history_load_more') }}</ button >
137+ </ div >
138+ </ div >
139+
93140 <!-- Transaction history -->
94141 < div class ="bg-white rounded-lg shadow ">
95142 < div class ="px-5 py-4 border-b ">
@@ -160,14 +207,19 @@ <h2 class="font-semibold">{{ _('me.transactions_title') }}</h2>
160207 rentals : [ ] ,
161208 machines : [ ] ,
162209 transactions : [ ] ,
210+ sessions : [ ] ,
163211 loading : true ,
164212 loadingRentals : true ,
165213 loadingMachines : true ,
166214 loadingTx : true ,
167215 loadingMoreTx : false ,
216+ loadingSessions : true ,
168217 txOffset : 0 ,
169218 txLimit : 50 ,
170219 hasMore : false ,
220+ sessionOffset : 0 ,
221+ sessionPageSize : 10 ,
222+ sessionHasMore : false ,
171223
172224 async init ( ) {
173225 try {
@@ -180,7 +232,7 @@ <h2 class="font-semibold">{{ _('me.transactions_title') }}</h2>
180232 return ;
181233 }
182234 this . loading = false ;
183- await Promise . all ( [ this . loadRentals ( ) , this . loadMachines ( ) , this . loadTx ( ) ] ) ;
235+ await Promise . all ( [ this . loadRentals ( ) , this . loadMachines ( ) , this . loadTx ( ) , this . loadSessions ( ) ] ) ;
184236 } ,
185237
186238 async loadRentals ( ) {
@@ -223,6 +275,31 @@ <h2 class="font-semibold">{{ _('me.transactions_title') }}</h2>
223275 this . loadingMoreTx = false ;
224276 } ,
225277
278+ async loadSessions ( ) {
279+ this . loadingSessions = true ;
280+ try {
281+ const r = await apiFetch ( `/api/v1/users/me/sessions?limit=${ this . sessionPageSize } &offset=${ this . sessionOffset } ` ) ;
282+ if ( r . ok ) {
283+ const data = await r . json ( ) ;
284+ this . sessions . push ( ...data ) ;
285+ this . sessionOffset += data . length ;
286+ this . sessionHasMore = data . length === this . sessionPageSize ;
287+ }
288+ } finally {
289+ this . loadingSessions = false ;
290+ }
291+ } ,
292+
293+ fmtDuration ( seconds ) {
294+ if ( seconds === null || seconds === undefined ) return '' ;
295+ const h = Math . floor ( seconds / 3600 ) ;
296+ const m = Math . floor ( ( seconds % 3600 ) / 60 ) ;
297+ const s = seconds % 60 ;
298+ if ( h > 0 ) return `${ h } h ${ m } m` ;
299+ if ( m > 0 ) return `${ m } m ${ s } s` ;
300+ return `${ s } s` ;
301+ } ,
302+
226303 txLabel ( type ) {
227304 return _TX_LABELS [ type ] || type ;
228305 } ,
0 commit comments