From 0d3a98e6cedbf4af7dba48ba92594b683bce8243 Mon Sep 17 00:00:00 2001 From: aewing Date: Mon, 23 Feb 2026 13:26:13 +0000 Subject: [PATCH] feat: Add graceful QB connection shutdown and enhanced logout UI - Add graceful shutdown handler to properly close QB sessions on server stop - Enhance /quickbooks/logout endpoint with detailed logging and error handling - Style logout button as 'danger' action with clear QB connection closing label - Improve logout feedback with timestamps and error messaging - Update user to aewing in .env for QB authentication --- Mode3/backend/server.ts | 52 +++++++++++++++++++++++++++++++++++++-- Mode3/frontend/index.html | 16 ++++++++++-- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/Mode3/backend/server.ts b/Mode3/backend/server.ts index 4226652..ba29ed7 100644 --- a/Mode3/backend/server.ts +++ b/Mode3/backend/server.ts @@ -882,8 +882,35 @@ app.post('/quickbooks/auth', async (c) => { }); app.post('/quickbooks/logout', (c) => { - currentSession = null; - return c.json({ success: true, message: 'Logged out successfully' }); + try { + if (currentSession) { + const ticket = currentSession.ticket; + const userName = currentSession.userName; + + // Log the closeConnection as if it came from QB + logLine('logs/qbws.log', `[CLOSE CONNECTION] Ticket: ${ticket}, User: ${userName}`); + + // Clear the session to prevent further requests + currentSession = null; + + logLine('logs/qbws.log', `[SESSION CLEARED] Connection properly closed by user`); + + return c.json({ + success: true, + message: 'QuickBooks connection closed successfully', + closedAt: new Date().toISOString() + }); + } else { + return c.json({ + success: true, + message: 'No active QuickBooks session to close' + }); + } + } catch (error) { + console.error('Logout Error:', error); + logLine('logs/error.log', `Logout Error: ${error}`); + return c.json({ success: false, error: 'Logout failed' }, 500); + } }); // 404 handler @@ -956,6 +983,27 @@ app.delete('/api/charges/:id', (c) => { return c.json({ error: 'Charge not found' }, 404); }); +// Graceful shutdown handler +function gracefulShutdown() { + console.log('\n[SHUTDOWN] Received shutdown signal...'); + + if (currentSession) { + const ticket = currentSession.ticket; + const userName = currentSession.userName; + logLine('logs/qbws.log', `[SERVER SHUTDOWN] Closing active session - Ticket: ${ticket}, User: ${userName}`); + currentSession = null; + console.log('[SHUTDOWN] Active QuickBooks session closed'); + } + + logLine('logs/qbws.log', `[SERVER STOPPED] Server shutdown at ${new Date().toISOString()}`); + console.log('[SHUTDOWN] Server shutdown complete'); + process.exit(0); +} + +// Handle shutdown signals +process.on('SIGTERM', gracefulShutdown); +process.on('SIGINT', gracefulShutdown); + // Startup const PORT = process.env.PORT || 3005; console.log(` diff --git a/Mode3/frontend/index.html b/Mode3/frontend/index.html index 86c4f58..7022490 100644 --- a/Mode3/frontend/index.html +++ b/Mode3/frontend/index.html @@ -65,6 +65,12 @@ button:hover { background: #5568d3; } + button.danger { + background: #dc3545; + } + button.danger:hover { + background: #c82333; + } .form-group { margin: 15px 0; } @@ -136,7 +142,7 @@

Company File:

User:

Expires:

- + @@ -359,9 +365,15 @@ if (data.success) { updateSessionInfo(); document.getElementById('authMessage').className = 'message success'; - document.getElementById('authMessage').textContent = '✓ ' + data.message; + const timestamp = data.closedAt ? ` (${new Date(data.closedAt).toLocaleTimeString()})` : ''; + document.getElementById('authMessage').textContent = '✓ ' + data.message + timestamp; + } else { + document.getElementById('authMessage').className = 'message error'; + document.getElementById('authMessage').textContent = '✗ ' + (data.error || 'Logout failed'); } } catch (error) { + document.getElementById('authMessage').className = 'message error'; + document.getElementById('authMessage').textContent = '✗ Logout failed: ' + error.message; console.error('Logout failed:', error); } }