From 673748ed2728b7dfb22f84e925fd2cd16b8629e7 Mon Sep 17 00:00:00 2001 From: Samir Boulahtit Date: Wed, 31 Dec 2025 23:41:43 +0100 Subject: [PATCH] feat: remember last visited page after login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users are now redirected to their last visited page after logging in, instead of always going to the dashboard. Implementation: - Track current page in localStorage on every page load - Exclude login, logout, onboarding, and error pages from tracking - On login success, redirect to last visited page if valid - Clear last visited page on logout Admin: - static/admin/js/init-alpine.js: Save page to admin_last_visited_page - static/admin/js/login.js: Redirect to last page after login - app/templates/admin/partials/header.html: Clear on logout Vendor: - static/vendor/js/init-alpine.js: Save page to vendor_last_visited_page - static/vendor/js/login.js: Redirect to last page (validates vendor code) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- app/templates/admin/partials/header.html | 1 + static/admin/js/init-alpine.js | 18 ++++++++++++++++++ static/admin/js/login.js | 14 +++++++++----- static/vendor/js/init-alpine.js | 14 ++++++++++++++ static/vendor/js/login.js | 14 ++++++++++++-- 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/app/templates/admin/partials/header.html b/app/templates/admin/partials/header.html index 95779832..91e03924 100644 --- a/app/templates/admin/partials/header.html +++ b/app/templates/admin/partials/header.html @@ -287,6 +287,7 @@ document.addEventListener('alpine:init', () => { // Clear admin tokens only (not vendor or customer tokens) localStorage.removeItem('admin_token'); localStorage.removeItem('admin_user'); + localStorage.removeItem('admin_last_visited_page'); // Note: Do NOT use localStorage.clear() - it would clear vendor/customer tokens too window.location.href = '/admin/login'; }); diff --git a/static/admin/js/init-alpine.js b/static/admin/js/init-alpine.js index 85828b2a..fe7d184c 100644 --- a/static/admin/js/init-alpine.js +++ b/static/admin/js/init-alpine.js @@ -57,6 +57,24 @@ function data() { } } + // ───────────────────────────────────────────────────────────────── + // Last visited page tracking (for redirect after login) + // ───────────────────────────────────────────────────────────────── + const LAST_PAGE_KEY = 'admin_last_visited_page'; + const currentPath = window.location.pathname; + + // Save current page (exclude login, logout, error pages) + if (currentPath.startsWith('/admin/') && + !currentPath.includes('/login') && + !currentPath.includes('/logout') && + !currentPath.includes('/errors/')) { + try { + window.localStorage.setItem(LAST_PAGE_KEY, currentPath); + } catch (e) { + // Ignore storage errors + } + } + // Map pages to their parent sections const pageSectionMap = { // Platform Administration diff --git a/static/admin/js/login.js b/static/admin/js/login.js index fd32247f..cf3da16a 100644 --- a/static/admin/js/login.js +++ b/static/admin/js/login.js @@ -183,14 +183,18 @@ function adminLogin() { this.success = 'Login successful! Redirecting...'; loginLog.info('Success message displayed to user'); - loginLog.info('Redirecting to dashboard immediately...'); + // Check for last visited page (saved before logout) + const lastPage = localStorage.getItem('admin_last_visited_page'); + const redirectTo = (lastPage && lastPage.startsWith('/admin/') && !lastPage.includes('/login')) + ? lastPage + : '/admin/dashboard'; + loginLog.info('=== EXECUTING REDIRECT ==='); - loginLog.debug('Target URL: /admin/dashboard'); - loginLog.debug('Redirect method: window.location.href'); + loginLog.debug('Last visited page:', lastPage); + loginLog.debug('Target URL:', redirectTo); // Use href instead of replace to allow back button - // But redirect IMMEDIATELY - don't wait! - window.location.href = '/admin/dashboard'; + window.location.href = redirectTo; } catch (error) { window.LogConfig.logError(error, 'Login'); diff --git a/static/vendor/js/init-alpine.js b/static/vendor/js/init-alpine.js index 307546ff..35b5d031 100644 --- a/static/vendor/js/init-alpine.js +++ b/static/vendor/js/init-alpine.js @@ -46,6 +46,19 @@ function data() { // Load vendor info this.loadVendorInfo(); + + // Save last visited page (for redirect after login) + // Exclude login, logout, onboarding, error pages + if (!path.includes('/login') && + !path.includes('/logout') && + !path.includes('/onboarding') && + !path.includes('/errors/')) { + try { + localStorage.setItem('vendor_last_visited_page', path); + } catch (e) { + // Ignore storage errors + } + } }, async loadVendorInfo() { @@ -112,6 +125,7 @@ function data() { localStorage.removeItem('vendor_user'); localStorage.removeItem('currentUser'); localStorage.removeItem('vendorCode'); + localStorage.removeItem('vendor_last_visited_page'); // Note: Do NOT use localStorage.clear() - it would clear admin/customer tokens too console.log('🔄 Redirecting to login...'); diff --git a/static/vendor/js/login.js b/static/vendor/js/login.js index 38e0c645..1c353d05 100644 --- a/static/vendor/js/login.js +++ b/static/vendor/js/login.js @@ -123,10 +123,20 @@ function vendorLogin() { vendorLoginLog.debug('Token stored as vendor_token in localStorage'); this.success = 'Login successful! Redirecting...'; - vendorLoginLog.info('Redirecting to vendor dashboard...'); + + // Check for last visited page (saved before logout) + const lastPage = localStorage.getItem('vendor_last_visited_page'); + const validLastPage = lastPage && + lastPage.startsWith(`/vendor/${this.vendorCode}/`) && + !lastPage.includes('/login') && + !lastPage.includes('/onboarding'); + const redirectTo = validLastPage ? lastPage : `/vendor/${this.vendorCode}/dashboard`; + + vendorLoginLog.info('Last visited page:', lastPage); + vendorLoginLog.info('Redirecting to:', redirectTo); setTimeout(() => { - window.location.href = `/vendor/${this.vendorCode}/dashboard`; + window.location.href = redirectTo; }, 1000); } catch (error) {