/** * Token Status UI - Standalone * Displays token statuses, expiration times, last 4 digits * No external imports - uses window.JobInfoAuth from global scope */ class TokenStatusUI { constructor() { this.container = null; this.refreshInterval = null; } /** * Create and show token status UI */ create(containerId = 'app') { console.log('[TokenUI] create() called with container:', containerId); this.container = document.getElementById(containerId); if (!this.container) { console.error('[TokenUI] Container not found:', containerId); return; } this.render(); // Refresh UI every second to update expiration countdown this.refreshInterval = window.setInterval(() => { this.render(); }, 1000); console.log('[TokenUI] UI created and refresh interval started'); } /** * Render token status UI */ render() { if (!this.container) return; const state = this.getState(); const pbStatus = state.pbUser.active ? '✓ Active' : '✗ Inactive'; const pbStatusColor = state.pbUser.active ? '#10b981' : '#ef4444'; const graphStatus = state.graphUser.active ? '✓ Active' : '○ Not Required'; const graphStatusColor = state.graphUser.active ? '#10b981' : '#6b7280'; this.container.innerHTML = `

Job Info Auth

User: ${state.userDisplayName}

PocketBase User Token

${pbStatus}

Token: ...${state.pbUser.lastFour}

Expires in: ${state.pbUser.expiresIn}

Microsoft Graph Token

${graphStatus}
${state.graphUser.active ? `

Token: ...${state.graphUser.lastFour}

Expires in: ${state.graphUser.expiresIn}

` : `

Graph token is optional. Login proceeded without it.

`}
Debug Info:
pb-user: ${state.pbUser.active ? 'active' : 'inactive'} | graph-user: ${state.graphUser.active ? 'active' : 'inactive'}
`; } /** * Get current token state */ getState() { if (!window.JobInfoAuth) { return { pbUser: { active: false, lastFour: 'none', expiresIn: 'unknown' }, graphUser: { active: false, lastFour: 'none', expiresIn: 'unknown' }, userDisplayName: 'Unknown' }; } const auth = window.JobInfoAuth; const authState = auth.getState(); const calculateTimeLeft = (expiresAt) => { if (!expiresAt) return 'unknown'; const now = Date.now(); const diff = expiresAt - now; if (diff < 0) return 'expired'; const hours = Math.floor(diff / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; }; return { pbUser: { active: !!authState['pb-user'], lastFour: authState['pb-user']?.lastFourDigits || 'none', expiresIn: calculateTimeLeft(authState['pb-user']?.expiresAt), expiresAt: authState['pb-user']?.expiresAt }, graphUser: { active: !!authState['graph-user'], lastFour: authState['graph-user']?.lastFourDigits || 'none', expiresIn: calculateTimeLeft(authState['graph-user']?.expiresAt), expiresAt: authState['graph-user']?.expiresAt }, userDisplayName: authState.userDisplayName || 'Unknown' }; } /** * Destroy UI and cleanup */ destroy() { if (this.refreshInterval) { clearInterval(this.refreshInterval); } } } // Create singleton instance const TokenUI = new TokenStatusUI(); // Expose globally if (typeof window !== 'undefined') { window.TokenUI = TokenUI; }