From 27f57ff9256aecc9fd21c4d3377325297c1cc515 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 28 Jun 2026 15:04:39 +0900 Subject: [PATCH] fix: guarantee loading indicator hides with 3-second timeout **Issue**: Loading indicator remained visible, intercepting all user interactions (pointer-events: auto blocks clicks) **Root cause**: Multiple detection methods insufficient, race condition between JavaScript execution and Blazor initialization **Solution**: Add guaranteed 3-second timeout + multiple detection methods - Method 1: 3000ms timeout (guaranteed) - Method 2: Detect when 10+ MudBlazor components appear - Method 3: Hide when readystatechange to 'interactive' or 'complete' **Failsafe**: Even if Blazor never fires events, loading WILL hide after 3 seconds max **Result**: - Loading shows: immediate on page load - Loading hides: within 1-3 seconds (whichever is first) - User can interact: guaranteed by 3-second timeout at latest Co-Authored-By: Claude Sonnet 4.6 --- TaxBaik.Web/wwwroot/js/admin-session.js | 46 ++++++++++--------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/TaxBaik.Web/wwwroot/js/admin-session.js b/TaxBaik.Web/wwwroot/js/admin-session.js index 9df2e4f..cc87b6a 100644 --- a/TaxBaik.Web/wwwroot/js/admin-session.js +++ b/TaxBaik.Web/wwwroot/js/admin-session.js @@ -15,47 +15,37 @@ window.taxbaikAdminSession = { window.taxbaikAdminSession.syncRouteClass(); window.addEventListener('popstate', window.taxbaikAdminSession.syncRouteClass); - // Show loading indicator on page load, hide when content renders + // Hide loading indicator after Blazor initializes const loadingOverlay = document.getElementById('blazor-loading'); if (loadingOverlay) { - // Hide loading when page is fully interactive - // Watch for Blazor components to render const hideLoading = () => { - loadingOverlay.classList.remove('show'); - document.removeEventListener('blazor:ready', hideLoading); - observer.disconnect(); + if (loadingOverlay.classList.contains('show')) { + loadingOverlay.classList.remove('show'); + } }; - // Hide on Blazor ready event - document.addEventListener('blazor:ready', hideLoading); + // Method 1: Hide after 3 seconds (guaranteed timeout) + setTimeout(hideLoading, 3000); - // Also hide after DOM content loaded + small delay - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', () => { - setTimeout(() => { - if (loadingOverlay.classList.contains('show')) { - hideLoading(); - } - }, 500); - }); - } else { - setTimeout(() => { - if (loadingOverlay.classList.contains('show')) { - hideLoading(); - } - }, 500); - } - - // Watch for interactive elements to appear + // Method 2: Hide when Blazor components appear (faster if available) const observer = new MutationObserver(() => { const mudElements = document.querySelectorAll('[class*="mud-"]').length; - if (mudElements > 20 && loadingOverlay.classList.contains('show')) { + if (mudElements > 10) { hideLoading(); + observer.disconnect(); } }); observer.observe(document.body, { childList: true, - subtree: true + subtree: true, + attributes: true + }); + + // Method 3: Hide when page is interactive + document.addEventListener('readystatechange', () => { + if (document.readyState === 'interactive' || document.readyState === 'complete') { + setTimeout(hideLoading, 500); + } }); }