class SessionManager{constructor(){this.isAuthenticated=false;this.maxInactiveMinutes=30;this.heartbeatInterval=5*60*1000;this.warningTime=5*60*1000;this.checkInterval=30*1000;this.heartbeatTimer=null;this.statusCheckTimer=null;this.warningShown=false;this.sessionWarningModal=null;this.init();} async init(){try{await this.checkAuthenticationStatus();if(this.isAuthenticated){this.startSessionMonitoring();this.createWarningModal();console.log('đ Session Manager gestartet');console.log(`đ Max Inaktivität:${this.maxInactiveMinutes}Minuten`);console.log(`đ Heartbeat Intervall:${this.heartbeatInterval/1000/60}Minuten`);}else{console.log('đ¤ Benutzer nicht angemeldet - Session Manager inaktiv');}}catch(error){console.error('â Session Manager Initialisierung fehlgeschlagen:',error);}} async checkAuthenticationStatus(){try{const response=await fetch('/api/session/status',{method:'GET',headers:{'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'}});if(response.ok){const data=await response.json();if(data.success){this.isAuthenticated=true;this.maxInactiveMinutes=data.session.max_inactive_minutes;console.log('â Session Status:',{user:data.user.email,timeLeft:Math.floor(data.session.time_left_seconds/60)+' Minuten',lastActivity:new Date(data.session.last_activity).toLocaleString('de-DE')});return data;}}else if(response.status===401){this.isAuthenticated=false;this.handleSessionExpired('Authentication check failed');}}catch(error){console.error('â Fehler beim PrĂźfen des Session-Status:',error);this.isAuthenticated=false;} return null;} startSessionMonitoring(){this.heartbeatTimer=setInterval(()=>{this.sendHeartbeat();},this.heartbeatInterval);this.statusCheckTimer=setInterval(()=>{this.checkSessionStatus();},this.checkInterval);setTimeout(()=>this.sendHeartbeat(),1000);} async sendHeartbeat(){try{const csrfToken=document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');const headers={'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'};if(csrfToken){headers['X-CSRFToken']=csrfToken;} const response=await fetch('/api/session/heartbeat',{method:'POST',headers:headers,body:JSON.stringify({timestamp:new Date().toISOString(),page:window.location.pathname,csrf_token:csrfToken})});if(response.ok){const data=await response.json();if(data.success){console.log('đ Heartbeat gesendet - Session aktiv:',Math.floor(data.time_left_seconds/60)+' Minuten verbleibend');}else{console.warn('â ď¸ Heartbeat fehlgeschlagen:',data);}}else if(response.status===401){this.handleSessionExpired('Heartbeat failed - unauthorized');}else if(response.status===400){console.warn('â ď¸ CSRF-Token Problem beim Heartbeat - versuche Seite neu zu laden');setTimeout(()=>location.reload(),5000);}}catch(error){console.error('â Heartbeat-Fehler:',error);}} async checkSessionStatus(){try{const sessionData=await this.checkAuthenticationStatus();if(sessionData&&sessionData.session){const timeLeftSeconds=sessionData.session.time_left_seconds;const timeLeftMinutes=Math.floor(timeLeftSeconds/60);if(timeLeftSeconds<=this.warningTime/1000&&timeLeftSeconds>0){if(!this.warningShown){this.showSessionWarning(timeLeftMinutes);this.warningShown=true;}}else if(timeLeftSeconds<=0){this.handleSessionExpired('Session time expired');}else{this.warningShown=false;this.hideSessionWarning();} this.updateSessionStatusDisplay(sessionData);}}catch(error){console.error('â Session-Status-Check fehlgeschlagen:',error);}} showSessionWarning(minutesLeft){this.hideSessionWarning();this.showToast('Session läuft ab',`Ihre Session läuft in ${minutesLeft}Minuten ab.MĂśchten Sie verlängern?`,'warning',10000,[{text:'Verlängern',action:()=>this.extendSession()},{text:'Abmelden',action:()=>this.logout()}]);if(this.sessionWarningModal){this.sessionWarningModal.show();this.updateWarningModal(minutesLeft);} console.log(`â ď¸ Session-Warnung:${minutesLeft}Minuten verbleibend`);} hideSessionWarning(){if(this.sessionWarningModal){this.sessionWarningModal.hide();}} createWarningModal(){const modalHTML=`
`;document.body.insertAdjacentHTML('beforeend',modalHTML);document.getElementById('extendSessionBtn').addEventListener('click',()=>{this.extendSession();this.hideSessionWarning();});document.getElementById('logoutBtn').addEventListener('click',()=>{this.logout();});this.sessionWarningModal={element:document.getElementById('sessionWarningModal'),show:()=>{document.getElementById('sessionWarningModal').classList.remove('hidden');},hide:()=>{document.getElementById('sessionWarningModal').classList.add('hidden');}};} updateWarningModal(minutesLeft){const timeElement=document.getElementById('timeRemaining');if(timeElement){timeElement.textContent=minutesLeft;}} async extendSession(extendMinutes=30){try{const response=await fetch('/api/session/extend',{method:'POST',headers:{'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'},body:JSON.stringify({extend_minutes:extendMinutes})});if(response.ok){const data=await response.json();if(data.success){this.warningShown=false;this.showToast('Session verlängert',`Ihre Session wurde um ${data.extended_minutes}Minuten verlängert`,'success',5000);console.log('â Session verlängert:',data);}else{this.showToast('Fehler','Session konnte nicht verlängert werden','error');}}else if(response.status===401){this.handleSessionExpired('Extend session failed - unauthorized');}}catch(error){console.error('â Session-Verlängerung fehlgeschlagen:',error);this.showToast('Fehler','Session-Verlängerung fehlgeschlagen','error');}} async logout(){try{this.stopSessionMonitoring();const response=await fetch('/auth/logout',{method:'POST',headers:{'Content-Type':'application/json','X-Requested-With':'XMLHttpRequest'}});if(response.ok){window.location.href='/auth/login';}else{window.location.href='/auth/login';}}catch(error){console.error('â Logout-Fehler:',error);window.location.href='/auth/login';}} handleSessionExpired(reason){console.log('đ Session abgelaufen:',reason);this.stopSessionMonitoring();this.isAuthenticated=false;this.showToast('Session abgelaufen','Sie wurden automatisch abgemeldet. Bitte melden Sie sich erneut an.','warning',8000);setTimeout(()=>{window.location.href='/auth/login?reason=session_expired';},2000);} stopSessionMonitoring(){if(this.heartbeatTimer){clearInterval(this.heartbeatTimer);this.heartbeatTimer=null;} if(this.statusCheckTimer){clearInterval(this.statusCheckTimer);this.statusCheckTimer=null;} console.log('đ Session-Monitoring gestoppt');} updateSessionStatusDisplay(sessionData){const statusElement=document.getElementById('sessionStatus');if(statusElement){const timeLeftMinutes=Math.floor(sessionData.session.time_left_seconds/60);statusElement.textContent=`Session:${timeLeftMinutes}min`;if(timeLeftMinutes<=5){statusElement.className='text-red-600 font-medium';}else if(timeLeftMinutes<=10){statusElement.className='text-yellow-600 font-medium';}else{statusElement.className='text-green-600 font-medium';}}} showToast(title,message,type='info',duration=5000,actions=[]){if(window.showToast){window.showToast(message,type,duration);return;} if(type==='error'||type==='warning'){alert(`${title}:${message}`);}else{console.log(`${title}:${message}`);}} isLoggedIn(){return this.isAuthenticated;} start(){if(!this.heartbeatTimer&&this.isAuthenticated){this.startSessionMonitoring();}} stop(){this.stopSessionMonitoring();} async extend(minutes=30){return await this.extendSession(minutes);} async logoutUser(){return await this.logout();}} document.addEventListener('DOMContentLoaded',()=>{if(!window.location.pathname.includes('/auth/login')){window.sessionManager=new SessionManager();window.addEventListener('beforeunload',()=>{if(window.sessionManager){window.sessionManager.stop();}});document.addEventListener('visibilitychange',()=>{if(window.sessionManager&&window.sessionManager.isLoggedIn()){if(document.hidden){console.log('đ Tab versteckt - Session-Monitoring reduziert');}else{console.log('đď¸ Tab sichtbar - Session-Check');setTimeout(()=>window.sessionManager.checkSessionStatus(),1000);}}});}});window.SessionManager=SessionManager;